Fixed #30628 -- Adjusted expression identity to differentiate bound fields.
Expressions referring to different bound fields should not be
considered equal.
Thanks Julien Enselme for the detailed report.
Regression in bc7e288ca9
.
This commit is contained in:
parent
1bbf77bea5
commit
ee6e93ec87
|
@ -376,7 +376,10 @@ class BaseExpression:
|
||||||
identity = [self.__class__]
|
identity = [self.__class__]
|
||||||
for arg, value in arguments:
|
for arg, value in arguments:
|
||||||
if isinstance(value, fields.Field):
|
if isinstance(value, fields.Field):
|
||||||
value = type(value)
|
if value.name and value.model:
|
||||||
|
value = (value.model._meta.label, value.name)
|
||||||
|
else:
|
||||||
|
value = type(value)
|
||||||
else:
|
else:
|
||||||
value = make_hashable(value)
|
value = make_hashable(value)
|
||||||
identity.append((arg, value))
|
identity.append((arg, value))
|
||||||
|
|
|
@ -9,4 +9,6 @@ Django 2.2.4 fixes several bugs in 2.2.3.
|
||||||
Bugfixes
|
Bugfixes
|
||||||
========
|
========
|
||||||
|
|
||||||
* ...
|
* Fixed a regression in Django 2.2 when ordering a ``QuerySet.union()``,
|
||||||
|
``intersection()``, or ``difference()`` by a field type present more than
|
||||||
|
once results in the wrong ordering being used (:ticket:`30628`).
|
||||||
|
|
|
@ -21,7 +21,7 @@ from django.db.models.functions import (
|
||||||
from django.db.models.sql import constants
|
from django.db.models.sql import constants
|
||||||
from django.db.models.sql.datastructures import Join
|
from django.db.models.sql.datastructures import Join
|
||||||
from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
|
from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
|
||||||
from django.test.utils import Approximate
|
from django.test.utils import Approximate, isolate_apps
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
UUID, UUIDPK, Company, Employee, Experiment, Number, RemoteEmployee,
|
UUID, UUIDPK, Company, Employee, Experiment, Number, RemoteEmployee,
|
||||||
|
@ -898,6 +898,7 @@ class ExpressionsTests(TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@isolate_apps('expressions')
|
||||||
class SimpleExpressionTests(SimpleTestCase):
|
class SimpleExpressionTests(SimpleTestCase):
|
||||||
|
|
||||||
def test_equal(self):
|
def test_equal(self):
|
||||||
|
@ -911,6 +912,15 @@ class SimpleExpressionTests(SimpleTestCase):
|
||||||
Expression(models.CharField())
|
Expression(models.CharField())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class TestModel(models.Model):
|
||||||
|
field = models.IntegerField()
|
||||||
|
other_field = models.IntegerField()
|
||||||
|
|
||||||
|
self.assertNotEqual(
|
||||||
|
Expression(TestModel._meta.get_field('field')),
|
||||||
|
Expression(TestModel._meta.get_field('other_field')),
|
||||||
|
)
|
||||||
|
|
||||||
def test_hash(self):
|
def test_hash(self):
|
||||||
self.assertEqual(hash(Expression()), hash(Expression()))
|
self.assertEqual(hash(Expression()), hash(Expression()))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -922,6 +932,15 @@ class SimpleExpressionTests(SimpleTestCase):
|
||||||
hash(Expression(models.CharField())),
|
hash(Expression(models.CharField())),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class TestModel(models.Model):
|
||||||
|
field = models.IntegerField()
|
||||||
|
other_field = models.IntegerField()
|
||||||
|
|
||||||
|
self.assertNotEqual(
|
||||||
|
hash(Expression(TestModel._meta.get_field('field'))),
|
||||||
|
hash(Expression(TestModel._meta.get_field('other_field'))),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ExpressionsNumericTests(TestCase):
|
class ExpressionsNumericTests(TestCase):
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,7 @@ class Cover(models.Model):
|
||||||
|
|
||||||
class Number(models.Model):
|
class Number(models.Model):
|
||||||
num = models.IntegerField()
|
num = models.IntegerField()
|
||||||
|
other_num = models.IntegerField(null=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.num)
|
return str(self.num)
|
||||||
|
|
|
@ -9,7 +9,7 @@ from .models import Number, ReservedName
|
||||||
class QuerySetSetOperationTests(TestCase):
|
class QuerySetSetOperationTests(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
Number.objects.bulk_create(Number(num=i) for i in range(10))
|
Number.objects.bulk_create(Number(num=i, other_num=10 - i) for i in range(10))
|
||||||
|
|
||||||
def number_transform(self, value):
|
def number_transform(self, value):
|
||||||
return value.num
|
return value.num
|
||||||
|
@ -251,3 +251,10 @@ class QuerySetSetOperationTests(TestCase):
|
||||||
qs1 = Number.objects.all()
|
qs1 = Number.objects.all()
|
||||||
qs2 = Number.objects.intersection(Number.objects.filter(num__gt=1))
|
qs2 = Number.objects.intersection(Number.objects.filter(num__gt=1))
|
||||||
self.assertEqual(qs1.difference(qs2).count(), 2)
|
self.assertEqual(qs1.difference(qs2).count(), 2)
|
||||||
|
|
||||||
|
def test_order_by_same_type(self):
|
||||||
|
qs = Number.objects.all()
|
||||||
|
union = qs.union(qs)
|
||||||
|
numbers = list(range(10))
|
||||||
|
self.assertNumbersEqual(union.order_by('num'), numbers)
|
||||||
|
self.assertNumbersEqual(union.order_by('other_num'), reversed(numbers))
|
||||||
|
|
|
@ -2335,7 +2335,7 @@ class ValuesQuerysetTests(TestCase):
|
||||||
qs = Number.objects.extra(select={'num2': 'num+1'}).annotate(Count('id'))
|
qs = Number.objects.extra(select={'num2': 'num+1'}).annotate(Count('id'))
|
||||||
values = qs.values_list(named=True).first()
|
values = qs.values_list(named=True).first()
|
||||||
self.assertEqual(type(values).__name__, 'Row')
|
self.assertEqual(type(values).__name__, 'Row')
|
||||||
self.assertEqual(values._fields, ('num2', 'id', 'num', 'id__count'))
|
self.assertEqual(values._fields, ('num2', 'id', 'num', 'other_num', 'id__count'))
|
||||||
self.assertEqual(values.num, 72)
|
self.assertEqual(values.num, 72)
|
||||||
self.assertEqual(values.num2, 73)
|
self.assertEqual(values.num2, 73)
|
||||||
self.assertEqual(values.id__count, 1)
|
self.assertEqual(values.id__count, 1)
|
||||||
|
|
Loading…
Reference in New Issue