Staramy się przyspieszyć naszą aplikację z prefetch_related
. Może on podążać za relacjami GenericForeignKey
i może pójść głębiej z __
, ale niestety nie powiedzie się, jeśli powiązany model nie ma takiego pola.Wiele pól do tej samej kolumny DB
Oto przykład modelowej struktury
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()
Więc ModelC
instancja może wskazywać albo ModelA
lub ModelB
. I mogę użyć takiego queryset wstępne pobieranie oba modele A i B: ModelC.objects.all().prefetch_related('content_object')
Niestety ja również wybrać obiekt zdarzenia (SomeModelA
lub SomeModelB
)
Jeśli próbuję uruchomić
ModelC.objects.all().prefetch_related('content_object', 'content_object__event_object')
to będzie działać, jeśli Występują tylko instancje ModelC
, które wskazują na ModelA
, ale w innym przypadku zakończy się niepowodzeniem, ponieważ ModelB
nie ma pola event_object
i zamiast tego ma .
Te modele są używane w wielu miejscach kodu, więc zmiana nazwy pola nie jest dobrym pomysłem. Zastanawiam się, czy istnieje sposób na stworzenie aliasu dla pola/kolumny.
starałem się zrobić tak:
class ModelB(models.Model):
event = models.ForeignKey(SomeModelB)
event_object = models.ForeignKey(SomeModelB, db_column='event_id', related_name='+')
zrobić dwa pola, które wskazują na tej samej kolumnie w tabeli DB. Jednak to nie działa, ponieważ łamie metodę save
. Django tworzy zapytanie SQL UPDATE
, w którym jedna kolumna jest umieszczona dwukrotnie i otrzymuje DatabaseError
Czy istnieje sposób na stworzenie takiego aliasu? A może jest jeszcze jedno rozwiązanie, które sprawi, że prefetch_related
nie będzie wyrzucać wyjątku?
Aktualizacja W save
metodzie istnieje parametr update_fields
, które mogą być stosowane w celu wykluczenia tego pola. Jednak został wprowadzony w wersji 1.5 i używamy wersji 1.4. Dlatego nadal szukam odpowiedzi.
Aktualizacja # 2: @ shx2 poprosił mnie o podanie informacji zwrotnej. Istnieją dwa możliwe przejścia zwrotne. 1-ty - gdy atrybut brakuje pierwszego obiektu:
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()
A jeśli prefetch_related parametry są ważne dla pierwszego obiektu następnie uzyskać 2nd traceback:
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'
Czy możesz dodać ślad zwrotny błędu 'prefetch_related'? – shx2
Dlaczego potrzebujesz zestawu zapytań ModelC? Nie możesz po prostu zrobić 2 różnych zapytań i traktować je osobno? Wiem, że moje pytanie jest trochę naiwne, ale czasami problemem jest to, jak stajemy w obliczu tych trudności. – marianobianchi
@marianobianchi nie, staramy się zoptymalizować jakąś część django admin, więc potrzebujemy pojedynczego zapytania. Również powyższe modele są uproszczone, mamy głębsze relacje w rzeczywistym projekcie – Igor