TL;DRこれは Django 1.7 のバグで、Django 1.8 で修正されました。
変更は master に直接適用され、非推奨期間にはなりませんでした。ここで下位互換性を維持することは非常に困難であったことを考えると、これはそれほど驚くべきことではありません。さらに驚くべきことに、1.8 のリリース ノートにはこの問題についての言及がありませんでした。これは、修正により現在動作中のコードの動作が変更されるためです。
この回答の残りの部分は、を使用してコミットを見つけた方法の説明ですgit bisect run
。何よりも私自身の参照のためにここにあるので、大きなプロジェクトを再び分割する必要がある場合は、ここに戻ることができます.
最初に、問題を再現するために django クローンとテスト プロジェクトをセットアップします。ここではvirtualenvwrapperを使用しましたが、必要に応じて分離を行うことができます。
cd /tmp
git clone https://github.com/django/django.git
cd django
git checkout tags/1.7
mkvirtualenv djbisect
export PYTHONPATH=/tmp/django # get django clone into sys.path
python ./django/bin/django-admin.py startproject djbisect
export PYTHONPATH=$PYTHONPATH:/tmp/django/djbisect # test project into sys.path
export DJANGO_SETTINGS_MODULE=djbisect.mysettings
次のファイルを作成します。
# /tmp/django/djbisect/djbisect/models.py
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
class GFKmodel(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
gfk = GenericForeignKey()
class GRmodel(models.Model):
related_gfk = GenericRelation(GFKmodel)
これも:
# /tmp/django/djbisect/djbisect/mysettings.py
from djbisect.settings import *
INSTALLED_APPS += ('djbisect',)
これで作業プロジェクトができました。test_script.py
使用する を作成しますgit bisect run
。
#!/usr/bin/env python
import subprocess, os, sys
db_fname = '/tmp/django/djbisect/db.sqlite3'
if os.path.exists(db_fname):
os.unlink(db_fname)
cmd = 'python /tmp/django/djbisect/manage.py migrate --noinput'
subprocess.check_call(cmd.split())
import django
django.setup()
from django.contrib.contenttypes.models import ContentType
from djbisect.models import GFKmodel, GRmodel
ct = ContentType.objects.get_for_model(GRmodel)
y = GRmodel.objects.create(pk=456)
x = GFKmodel.objects.create(pk=789, content_type=ct, object_id=y.pk)
query1 = GRmodel.objects.values_list('related_gfk', flat=1)
query2 = GRmodel.objects.values_list('related_gfk__pk', flat=1)
print(query1)
print(query2)
print(query1.query)
print(query2.query)
if query1[0] == 789 == query2[0]:
print('FIXED')
sys.exit(1)
else:
print('UNFIXED')
sys.exit(0)
スクリプトは実行可能である必要があるため、フラグをchmod +x test_script.py
. これは、Django のクローンが作成されたディレクトリ (つまり/tmp/django/test_script.py
、私の場合) に配置する必要があります。これはimport django
、site-packages からのバージョンではなく、ローカルでチェックアウトされた django プロジェクトを最初に取得する必要があるためです。
git bisect のユーザー インターフェイスは、バグが発生した場所を見つけるように設計されているため、特定のバグがいつ修正されたかを確認しようとする場合、通常の「悪い」と「良い」の接頭辞は逆になります。これは逆さまに見えるかもしれませんが、テスト スクリプトは、バグが存在する場合は成功 (戻りコード 0) で終了し、バグが修正されている場合は失敗します (0 以外の戻りコードで)。これは私を数回つまずかせました!
git bisect start --term-new=fixed --term-old=unfixed
git bisect fixed tags/1.8
git bisect unfixed tags/1.7
git bisect run ./test_script.py
したがって、このプロセスは自動検索を実行し、最終的にバグが修正されたコミットを見つけます。Django 1.7 と Django 1.8 の間で多くのコミットがあったため、時間がかかります。1362 のリビジョン、およそ 10 のステップを二分し、最終的に出力します。
1c5cbf5e5d5b350f4df4aca6431d46c767d3785a is the first fixed commit
commit 1c5cbf5e5d5b350f4df4aca6431d46c767d3785a
Author: Anssi Kääriäinen <akaariai@gmail.com>
Date: Wed Dec 17 09:47:58 2014 +0200
Fixed #24002 -- GenericRelation filtering targets related model's pk
Previously Publisher.objects.filter(book=val) would target
book.object_id if book is a GenericRelation. This is inconsistent to
filtering over reverse foreign key relations, where the target is the
related model's primary key.
それはまさに、クエリが間違った SQL (間違ったテーブルからデータを取得する) から変更されたコミットです。
SELECT "djbisect_gfkmodel"."object_id" FROM "djbisect_grmodel" LEFT OUTER JOIN "djbisect_gfkmodel" ON ( "djbisect_grmodel"."id" = "djbisect_gfkmodel"."object_id" AND ("djbisect_gfkmodel"."content_type_id" = 8) )
正しいバージョンに:
SELECT "djbisect_gfkmodel"."id" FROM "djbisect_grmodel" LEFT OUTER JOIN "djbisect_gfkmodel" ON ( "djbisect_grmodel"."id" = "djbisect_gfkmodel"."object_id" AND ("djbisect_gfkmodel"."content_type_id" = 8) )
もちろん、コミット ハッシュから、プル リクエストとチケットを github で簡単に見つけることができます。うまくいけば、これはいつか他の誰かにも役立つかもしれません.Djangoを二分することは、移行のためにセットアップが難しい場合があります.