でアプリを高速化しようとしていprefetch_related
ます。リレーションをたどることがGenericForeignKey
でき、さらに深くすることもできます__
が、関連するモデルにそのようなフィールドがない場合、残念ながら失敗します。
モデル構造の例を次に示します
class ModelA(models.Model):
event_object = models.ForeignKey(SomeModelA)
class ModelB(models.Model):
event = models.ForeignKey(SomeModelB)
class ModelC(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
したがってModelC
、インスタンスは または のいずれかを指すことができModelA
ますModelB
。そして、このようなクエリセットを使用して、A モデルと B モデルの両方をプリフェッチできます。ModelC.objects.all().prefetch_related('content_object')
残念ながら、イベント オブジェクト (SomeModelA
またはSomeModelB
)も選択する必要があります。
走ろうとしたら
ModelC.objects.all().prefetch_related('content_object', 'content_object__event_object')
ModelC
を指すインスタンスしかない場合は機能しますが、フィールドがなく代わりにあるModelA
ために失敗する場合があります。ModelB
event_object
event
このモデルはコード全体の多くの場所で使用されるため、フィールドの名前を変更することはお勧めできません。フィールド/列のエイリアスを作成する方法があるのだろうか。
私はこのようにしようとしていました:
class ModelB(models.Model):
event = models.ForeignKey(SomeModelB)
event_object = models.ForeignKey(SomeModelB, db_column='event_id', related_name='+')
DBテーブルの同じ列を指す2つのフィールドを作成します。ただし、これはsave
メソッドを壊すため機能しません。Django は、UPDATE
1 つの列が 2 回配置される SQL クエリを作成し、DatabaseError を取得します。
そのようなエイリアスを作成する方法はありますか? またはprefetch_related
、例外をスローしないようにする別の解決策があるでしょうか?
更新:save
メソッドには、update_fields
このフィールドを除外するために使用できるパラメーターがあります。ただし、1.5 で導入され、1.4 を使用しています。だから私は答えを探し続けます。
更新 #2 : @shx2 からトレースバックの提供を依頼されました。2 つの可能なトレースバックがあります。1st - 最初のオブジェクトに属性がない場合:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 72, in __repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 97, in __iter__
len(self)
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 89, in __len__
self._prefetch_related_objects()
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 570, in _prefetch_related_objects
prefetch_related_objects(self._result_cache, self._prefetch_related_lookups)
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 1664, in prefetch_related_objects
(attr, first_obj.__class__.__name__, lookup))
AttributeError: Cannot find 'event_object' on ModelB object, 'content_object__event_object' is an invalid parameter to prefetch_related()
そして、prefetch_related パラメーターが最初のオブジェクトに対して有効である場合、2 番目のトレースバックを取得します。
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 72, in __repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 97, in __iter__
len(self)
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 89, in __len__
self._prefetch_related_objects()
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 570, in _prefetch_related_objects
prefetch_related_objects(self._result_cache, self._prefetch_related_lookups)
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 1680, in prefetch_related_objects
obj_list, additional_prl = prefetch_one_level(obj_list, prefetcher, attr)
File "/home/igor/workspace/projectname/eggs/Django-1.4.2-py2.7.egg/django/db/models/query.py", line 1803, in prefetch_one_level
qs = getattr(obj, attname).all()
AttributeError: 'ModelB' object has no attribute 'event_object'