Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#25786 closed Bug (fixed)

set_*_order raises ValueError when ForeignKey referenced Model also has OneToOneField

Reported by: aktiur Owned by: Tim Graham
Component: Database layer (models, ORM) Version: 1.8
Severity: Release blocker Keywords: order_with_respect_to ForeignKey OneToOneField
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Hello everyone,

I came across a bug where trying to order models with respect to their ForeignKey raises a ValueError when the ForeignKey referenced model has a OneToOneField to another completely unrelated model.

Here is a stripped down version of my models that still triggers the bug

Code highlighting:

  from django.db import models
 
 
  class Entity(models.Model):
      pass


  class Dimension(models.Model):
      entity = models.OneToOneField('Entity', primary_key=True)


  class Component(models.Model):
      dimension = models.ForeignKey("Dimension")

      class Meta:
          order_with_respect_to = "dimension"

And here is the triggering code :

Code highlighting:

>>> e = Entity.objects.create
>>> d = Dimension.objects.create(entity=e)
>>> c1 = d.dimension_set.create()
>>> c2 = d.dimension_set.create()
>>> d.set_dimension_order([c1.id, c2.id])

It raises :

Exception:

  Traceback (most recent call last):
   File "<input>", line 1, in <module>
   File "C:\Miniconda3\envs\anap-mesis\lib\site-packages\django\utils\functional.py", line 17, in _curried
     return _curried_func(*(args + moreargs), **dict(kwargs, **morekwargs))
   File "C:\Miniconda3\envs\anap-mesis\lib\site-packages\django\db\models\base.py", line 1683, in method_set_order
     ordered_obj.objects.filter(**{'pk': j, order_name: rel_val}).update(_order=i)
   File "C:\Miniconda3\envs\anap-mesis\lib\site-packages\django\db\models\manager.py", line 127, in manager_method
     return getattr(self.get_queryset(), name)(*args, **kwargs)
   File "C:\Miniconda3\envs\anap-mesis\lib\site-packages\django\db\models\query.py", line 679, in filter
     return self._filter_or_exclude(False, *args, **kwargs)
   File "C:\Miniconda3\envs\anap-mesis\lib\site-packages\django\db\models\query.py", line 697, in _filter_or_exclude
     clone.query.add_q(Q(*args, **kwargs))
   File "C:\Miniconda3\envs\anap-mesis\lib\site-packages\django\db\models\sql\query.py", line 1309, in add_q
     clause, require_inner = self._add_q(where_part, self.used_aliases)
   File "C:\Miniconda3\envs\anap-mesis\lib\site-packages\django\db\models\sql\query.py", line 1337, in _add_q
     allow_joins=allow_joins, split_subq=split_subq,
   File "C:\Miniconda3\envs\anap-mesis\lib\site-packages\django\db\models\sql\query.py", line 1178, in build_filter
     self.check_related_objects(field, value, opts)
   File "C:\Miniconda3\envs\anap-mesis\lib\site-packages\django\db\models\sql\query.py", line 1073, in check_related_objects
     self.check_query_object_type(value, opts)
   File "C:\Miniconda3\envs\anap-mesis\lib\site-packages\django\db\models\sql\query.py", line 1057, in check_query_object_type
     (value, opts.object_name))
 ValueError: Cannot query "Entity object": Must be "Dimension" instance

I'm using Python 3.4.3 / Django 1.8.4.

I'm not very familiar with django's internals, but it seems to me that the bug happens in django.db.models.base, in method_set_order, on line 1677.
More precisely, I have noticed that :

Code excerpt:

>>> m.Component._meta.order_with_respect_to.rel
<ManyToOneRel: order.component>
>>> m.Component._meta.order_with_respect_to.rel.field_name
'entity'

Change History (6)

comment:1 Changed 4 years ago by Baptiste Mispelon

Severity: NormalRelease blocker
Triage Stage: UnreviewedAccepted

Hi,

The sample code you gave doesn't actually work but I managed to reproduce your issue using this:

class Test(TestCase):
    def test(self):
        e = Entity.objects.create()
        d = Dimension.objects.create(entity=e)
        c1 = d.component_set.create()
        c2 = d.component_set.create()
        d.set_component_order([c1.id, c2.id])
        self.assertQuerysetEqual(d.component_set.all(), [c1.id, c2.id], attrgetter('pk'))

I did some digging and this testcase worked in Django 1.7 (was broken in 1.8 by 34ba86706f0db33d9a0ab44e4abb78703e7262a9) but later got fixed by 7bec480fe2ace94c8e7f0c88485442bfa74436b4 (which will be part of 1.9).

I don't think we can simply backport 7bec480fe2ace94c8e7f0c88485442bfa74436b4 to the 1.8 branch though (because it's a new feature). We should figure out if we can extract just the part that fixed this regression and not the whole feature.

I'm marking this as a release blocker for 1.8 as a consequence.

Thanks.

comment:2 Changed 4 years ago by Tim Graham

Owner: changed from nobody to Tim Graham
Status: newassigned

comment:3 Changed 4 years ago by Tim Graham

Has patch: set

comment:4 Changed 4 years ago by Tim Graham <timograham@…>

Resolution: fixed
Status: assignedclosed

In 6d9f061b:

[1.8.x] Fixed #25786 -- Fixed set_FOO_order() crash with order_with_respect_to referencing OneToOneField pk.

Partial backport of 7bec480fe2ace94c8e7f0c88485442bfa74436b4 from master

comment:5 Changed 4 years ago by Tim Graham <timograham@…>

In e07def14:

Refs #25786 -- Added tests/release notes for set_FOO_order() crash with order_with_respect_to referencing OneToOneField pk.

Forwardport of 6d9f061b07ce7aa1a9da6799b3104971ee73998b from stable/1.8.x
The issue was fixed by 7bec480fe2ace94c8e7f0c88485442bfa74436b4.

comment:6 Changed 4 years ago by Tim Graham <timograham@…>

In 8edf8db:

[1.9.x] Refs #25786 -- Added tests/release notes for set_FOO_order() crash with order_with_respect_to referencing OneToOneField pk.

Forwardport of 6d9f061b07ce7aa1a9da6799b3104971ee73998b from stable/1.8.x
The issue was fixed by 7bec480fe2ace94c8e7f0c88485442bfa74436b4.

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