#15790 closed Bug (fixed)
only() broken for proxy models
Reported by: | Owned by: | Michał Modzelewski | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | proxy only |
Cc: | michal.modzelewski@… | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Usage of deferred fields with proxy models is broken.
For example when using the following models
class Item(models.Model): name = models.CharField(max_length=15) text = models.TextField(default="xyzzy") value = models.IntegerField() other_value = models.IntegerField(default=0) class Proxy(Item): class Meta: proxy = True
we create an item with
>>> proxy = Proxy.objects.create(name="proxy", value=42)
Now depending on whether we call only() with 'id' or not we get different behaviour.
Without 'id' we get an endless loop.
>>> deferredproxy = Proxy.objects.only('value').get(pk=proxy.pk) >>> deferredproxy.name Traceback (most recent call last): File "<stdin>", line 1, in <module> deferredproxy.name File "/home/michal/.local/lib/python2.7/site-packages/django/db/models/query_utils.py", line 100, in __get__ cls._base_manager.filter(pk=instance.pk).only(name).using( File "/home/michal/.local/lib/python2.7/site-packages/django/db/models/base.py", line 426, in _get_pk_val return getattr(self, meta.pk.attname) File "/home/michal/.local/lib/python2.7/site-packages/django/db/models/query_utils.py", line 100, in __get__ cls._base_manager.filter(pk=instance.pk).only(name).using( ... File "/home/michal/.local/lib/python2.7/site-packages/django/db/models/base.py", line 426, in _get_pk_val return getattr(self, meta.pk.attname) RuntimeError: maximum recursion depth exceeded
With 'id' we get the wrong value when accessing a deferred field.
>>> deferredproxy = Proxy.objects.only('id', 'value').get(pk=proxy.pk) >>> deferredproxy.name 3
This value happens to be the object id.
>>> proxy.id 3
Comparing the objects returned with examples using the base model.
>>> Proxy.objects.only('other_value').get(pk=proxy.pk).__dict__ {'_state': <django.db.models.base.ModelState object at 0x89bd58c>, 'other_value': 3} >>> Item.objects.only('other_value').get(pk=proxy.pk).__dict__ {'_state': <django.db.models.base.ModelState object at 0x89bd80c>, 'id': 3, 'other_value': 0} >>> Proxy.objects.only('name', 'text', 'value', 'other_value').get(pk=proxy.pk).__dict__ {'text': u'proxy', '_state': <django.db.models.base.ModelState object at 0x89bda8c>, 'name': 3, 'value': u'xyzzy', 'other_value': 42} >>> Item.objects.only('name', 'text', 'value', 'other_value').get(pk=proxy.pk).__dict__ {'name': u'proxy', 'text': u'xyzzy', '_state': <django.db.models.base.ModelState object at 0x89bdcec>, 'value': 42, 'other_value': 0, 'id': 3}
'id' is missing from the __dict__ for the proxy models, and all the values are shifted.
Attachments (2)
Change History (9)
by , 14 years ago
Attachment: | 15790_only_broken_for_proxy_models.diff added |
---|
comment:1 by , 14 years ago
Has patch: | set |
---|---|
milestone: | → 1.3 |
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 14 years ago
Severity: | Release blocker → Normal |
---|
I don't think this is a release blocker, as it is not a regression, or a serious bug with a new feature in 1.3 that would have blocked it.
comment:3 by , 14 years ago
Yes, i originally thought that this could result in an unintentional loss of data if you saved such a broken model instance, but since the pk value is missing from the __dict__ saving will just create a new record in the database.
comment:4 by , 14 years ago
Easy pickings: | unset |
---|---|
milestone: | 1.3 → 1.4 |
Owner: | changed from | to
Status: | new → assigned |
by , 14 years ago
Attachment: | 15790_only_broken_for_proxy_models.2.diff added |
---|
Updated patch for trunk
comment:5 by , 14 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
Patch applies cleanly and the described issue is fixed.
Patch for this bug, with regression tests