Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#15790 closed Bug (fixed)

only() broken for proxy models

Reported by: michal.modzelewski@… Owned by: michalm
Component: Database layer (models, ORM) Version: master
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:


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(
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/michal/.local/lib/python2.7/site-packages/django/db/models/", line 100, in __get__
  File "/home/michal/.local/lib/python2.7/site-packages/django/db/models/", line 426, in _get_pk_val
    return getattr(self,
  File "/home/michal/.local/lib/python2.7/site-packages/django/db/models/", line 100, in __get__
  File "/home/michal/.local/lib/python2.7/site-packages/django/db/models/", line 426, in _get_pk_val
    return getattr(self,
RuntimeError: maximum recursion depth exceeded

With 'id' we get the wrong value when accessing a deferred field.

>>> deferredproxy = Proxy.objects.only('id', 'value').get(

This value happens to be the object id.


Comparing the objects returned with examples using the base model.

>>> Proxy.objects.only('other_value').get(
{'_state': <django.db.models.base.ModelState object at 0x89bd58c>, 'other_value': 3}
>>> Item.objects.only('other_value').get(
{'_state': <django.db.models.base.ModelState object at 0x89bd80c>, 'id': 3, 'other_value': 0}
>>> Proxy.objects.only('name', 'text', 'value', 'other_value').get(
{'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(
{'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)

15790_only_broken_for_proxy_models.diff (2.6 KB) - added by michal.modzelewski@… 4 years ago.
Patch for this bug, with regression tests
15790_only_broken_for_proxy_models.2.diff (2.7 KB) - added by michalm 4 years ago.
Updated patch for trunk

Download all attachments as: .zip

Change History (9)

Changed 4 years ago by michal.modzelewski@…

Patch for this bug, with regression tests

comment:1 Changed 4 years ago by michal.modzelewski@…

  • Has patch set
  • milestone set to 1.3
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

comment:2 Changed 4 years ago by lukeplant

  • Severity changed from Release blocker to 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 Changed 4 years ago by Michał Modzelewski <michal.modzelewski@…>

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 Changed 4 years ago by michalm

  • Easy pickings unset
  • milestone changed from 1.3 to 1.4
  • Owner changed from nobody to michalm
  • Status changed from new to assigned

Changed 4 years ago by michalm

Updated patch for trunk

comment:5 Changed 4 years ago by kgibula

  • Triage Stage changed from Accepted to Ready for checkin

Patch applies cleanly and the described issue is fixed.

comment:6 Changed 4 years ago by ramiro

  • Resolution set to fixed
  • Status changed from assigned to closed

In [16228]:

Fixed #15790 -- Fixed QuerySet only() and defer() methods behavior with proxy models. Thanks Michal Modzelewzki for the report and patch.

comment:7 Changed 4 years ago by jacob

  • milestone 1.4 deleted

Milestone 1.4 deleted

Note: See TracTickets for help on using tickets.
Back to Top