python - Multiple fields to the same DB column -
we trying speed our app prefetch_related. can follow genericforeignkey relations, , can go deeper __ unfortunately fail if related model not have such field.
here example of model structure
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() so modelc instance can point either modela or modelb. , can use such queryset prefetch both , b models: modelc.objects.all().prefetch_related('content_object') unfortunately need select event object (somemodela or somemodelb)
if try run
modelc.objects.all().prefetch_related('content_object', 'content_object__event_object') it work if have modelc instances points modela, in ohter case fail because modelb not have event_object field , have event instead.
this models used in many places across code it's not idea rename field. wonder if there way create alias field/column.
i trying this:
class modelb(models.model): event = models.foreignkey(somemodelb) event_object = models.foreignkey(somemodelb, db_column='event_id', related_name='+') to make 2 fields point same column in db table. not working breaks save method. django creates update sql query 1 column placed twice , gets databaseerror
is there way create such alias? or maybe there solution make prefetch_related not throw exception?
update: in save method there update_fields parameter can used exclude field. introduced in 1.5 , using 1.4. continue search answer.
update #2: @shx2 asked me provide traceback. there 2 possible traceback. 1st - when attribute missing on first object:
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' invalid parameter prefetch_related() and if prefetch_related parameters valid first object 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'
it looks bug or oversight in django. workaround, can try defining custom manager 2-stage prefetching.
from django.db import models django.db.models import q django.contrib.contenttypes.models import contenttype class prefetchworkaroundmanager(models.manager): def get_queryset(self): q = super(prefetchworkaroundmanager, self).get_queryset() content_typea = contenttype.objects.get_for_model(modela) content_typeb = contenttype.objects.get_for_model(modelb) return q.filter(content_type__pk = content_typea.id).prefetch_related('content_object', 'content_object__event_object') | \ q.filter(content_type__pk = content_typeb.id).prefetch_related('content_object', 'content_object__event') class modelc(models.model): ... objects_prefetched = prefetchworkaroundmanager() each caller wants prefetching take place should access modelc.objects_prefetched instead of modelc.objects:
modelc.objects_prefetched.filter(...) i admit, didn't test it, doesn't work as-is. believe approach sound.
Comments
Post a Comment