Kaydet (Commit) 6d9f061b authored tarafından Tim Graham's avatar Tim Graham

[1.8.x] Fixed #25786 -- Fixed set_FOO_order() crash with order_with_respect_to…

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

Partial backport of 7bec480f from master
üst 8f724817
......@@ -1674,13 +1674,13 @@ class Model(six.with_metaclass(ModelBase)):
def method_set_order(ordered_obj, self, id_list, using=None):
if using is None:
using = DEFAULT_DB_ALIAS
rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
order_name = ordered_obj._meta.order_with_respect_to.name
order_wrt = ordered_obj._meta.order_with_respect_to
filter_args = order_wrt.get_forward_related_filter(self)
# FIXME: It would be nice if there was an "update many" version of update
# for situations like this.
with transaction.atomic(using=using, savepoint=False):
for i, j in enumerate(id_list):
ordered_obj.objects.filter(**{'pk': j, order_name: rel_val}).update(_order=i)
ordered_obj.objects.filter(pk=j, **filter_args).update(_order=i)
def method_get_order(ordered_obj, self):
......
......@@ -314,6 +314,19 @@ class RelatedField(Field):
else:
self.do_related_class(other, cls)
def get_forward_related_filter(self, obj):
"""
Return the keyword arguments that when supplied to
self.model.object.filter(), would select all instances related through
this field to the remote obj. This is used to build the querysets
returned by related descriptors. obj is an instance of
self.related_field.model.
"""
return {
'%s__%s' % (self.name, rh_field.name): getattr(obj, rh_field.attname)
for _, rh_field in self.related_fields
}
@property
def swappable_setting(self):
"""
......
......@@ -42,3 +42,7 @@ Bugfixes
* Fixed a duplicate query regression in 1.8 on proxied model deletion
(:ticket:`25685`).
* Fixed ``set_FOO_order()`` crash when the ``ForeignKey`` of a model with
``order_with_respect_to`` references a model with a ``OneToOneField``
primary key (:ticket:`25786`).
......@@ -33,3 +33,19 @@ class Post(models.Model):
def __str__(self):
return self.title
# order_with_respect_to points to a model with a OneToOneField primary key.
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'
......@@ -5,7 +5,7 @@ from operator import attrgetter
from django.db import models
from django.test import TestCase
from .models import Answer, Post, Question
from .models import Answer, Dimension, Entity, Post, Question
class OrderWithRespectToTests(TestCase):
......@@ -103,3 +103,13 @@ class OrderWithRespectToTests2(TestCase):
count += 1
self.assertEqual(count, 1)
class TestOrderWithRespectToOneToOnePK(TestCase):
def test_set_order(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'))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment