1
0
mirror of https://github.com/django/django.git synced 2025-10-24 06:06:09 +00:00

Fixed #30621 -- Fixed crash of __contains lookup for Date/DateTimeRangeField when the right hand side is the same type.

Thanks Tilman Koschnick for the report and initial patch.
Thanks Carlton Gibson the review.

Regression in 6b048b364c.
This commit is contained in:
Mariusz Felisiak
2019-07-10 10:33:36 +02:00
committed by GitHub
parent ee6e93ec87
commit 7991111af1
6 changed files with 76 additions and 3 deletions

View File

@@ -211,7 +211,9 @@ class Migration(migrations.Migration):
('bigints', BigIntegerRangeField(null=True, blank=True)),
('decimals', DecimalRangeField(null=True, blank=True)),
('timestamps', DateTimeRangeField(null=True, blank=True)),
('timestamps_inner', DateTimeRangeField(null=True, blank=True)),
('dates', DateRangeField(null=True, blank=True)),
('dates_inner', DateRangeField(null=True, blank=True)),
],
options={
'required_db_vendor': 'postgresql'

View File

@@ -135,7 +135,9 @@ class RangesModel(PostgreSQLModel):
bigints = BigIntegerRangeField(blank=True, null=True)
decimals = DecimalRangeField(blank=True, null=True)
timestamps = DateTimeRangeField(blank=True, null=True)
timestamps_inner = DateTimeRangeField(blank=True, null=True)
dates = DateRangeField(blank=True, null=True)
dates_inner = DateRangeField(blank=True, null=True)
class RangeLookupsModel(PostgreSQLModel):

View File

@@ -1,5 +1,7 @@
import datetime
from django.db import connection, transaction
from django.db.models import Q
from django.db.models import F, Q
from django.db.models.constraints import CheckConstraint
from django.db.utils import IntegrityError
@@ -33,3 +35,51 @@ class SchemaTests(PostgreSQLTestCase):
with self.assertRaises(IntegrityError), transaction.atomic():
RangesModel.objects.create(ints=(20, 50))
RangesModel.objects.create(ints=(10, 30))
def test_check_constraint_daterange_contains(self):
constraint_name = 'dates_contains'
self.assertNotIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
constraint = CheckConstraint(
check=Q(dates__contains=F('dates_inner')),
name=constraint_name,
)
with connection.schema_editor() as editor:
editor.add_constraint(RangesModel, constraint)
with connection.cursor() as cursor:
constraints = connection.introspection.get_constraints(cursor, RangesModel._meta.db_table)
self.assertIn(constraint_name, constraints)
date_1 = datetime.date(2016, 1, 1)
date_2 = datetime.date(2016, 1, 4)
with self.assertRaises(IntegrityError), transaction.atomic():
RangesModel.objects.create(
dates=(date_1, date_2),
dates_inner=(date_1, date_2.replace(day=5)),
)
RangesModel.objects.create(
dates=(date_1, date_2),
dates_inner=(date_1, date_2),
)
def test_check_constraint_datetimerange_contains(self):
constraint_name = 'timestamps_contains'
self.assertNotIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
constraint = CheckConstraint(
check=Q(timestamps__contains=F('timestamps_inner')),
name=constraint_name,
)
with connection.schema_editor() as editor:
editor.add_constraint(RangesModel, constraint)
with connection.cursor() as cursor:
constraints = connection.introspection.get_constraints(cursor, RangesModel._meta.db_table)
self.assertIn(constraint_name, constraints)
datetime_1 = datetime.datetime(2016, 1, 1)
datetime_2 = datetime.datetime(2016, 1, 2, 12)
with self.assertRaises(IntegrityError), transaction.atomic():
RangesModel.objects.create(
timestamps=(datetime_1, datetime_2),
timestamps_inner=(datetime_1, datetime_2.replace(hour=13)),
)
RangesModel.objects.create(
timestamps=(datetime_1, datetime_2),
timestamps_inner=(datetime_1, datetime_2),
)

View File

@@ -115,11 +115,15 @@ class TestRangeContainsLookup(PostgreSQLTestCase):
]
cls.obj = RangesModel.objects.create(
dates=(cls.dates[0], cls.dates[3]),
dates_inner=(cls.dates[1], cls.dates[2]),
timestamps=(cls.timestamps[0], cls.timestamps[3]),
timestamps_inner=(cls.timestamps[1], cls.timestamps[2]),
)
cls.aware_obj = RangesModel.objects.create(
dates=(cls.dates[0], cls.dates[3]),
dates_inner=(cls.dates[1], cls.dates[2]),
timestamps=(cls.aware_timestamps[0], cls.aware_timestamps[3]),
timestamps_inner=(cls.timestamps[1], cls.timestamps[2]),
)
# Objects that don't match any queries.
for i in range(3, 4):
@@ -140,6 +144,7 @@ class TestRangeContainsLookup(PostgreSQLTestCase):
(self.aware_timestamps[1], self.aware_timestamps[2]),
Value(self.dates[0], output_field=DateTimeField()),
Func(F('dates'), function='lower', output_field=DateTimeField()),
F('timestamps_inner'),
)
for filter_arg in filter_args:
with self.subTest(filter_arg=filter_arg):
@@ -154,6 +159,7 @@ class TestRangeContainsLookup(PostgreSQLTestCase):
(self.dates[1], self.dates[2]),
Value(self.dates[0], output_field=DateField()),
Func(F('timestamps'), function='lower', output_field=DateField()),
F('dates_inner'),
)
for filter_arg in filter_args:
with self.subTest(filter_arg=filter_arg):
@@ -361,7 +367,9 @@ class TestSerialization(PostgreSQLSimpleTestCase):
'\\"bounds\\": \\"[)\\"}", "decimals": "{\\"empty\\": true}", '
'"bigints": null, "timestamps": "{\\"upper\\": \\"2014-02-02T12:12:12+00:00\\", '
'\\"lower\\": \\"2014-01-01T00:00:00+00:00\\", \\"bounds\\": \\"[)\\"}", '
'"dates": "{\\"upper\\": \\"2014-02-02\\", \\"lower\\": \\"2014-01-01\\", \\"bounds\\": \\"[)\\"}" }, '
'"timestamps_inner": null, '
'"dates": "{\\"upper\\": \\"2014-02-02\\", \\"lower\\": \\"2014-01-01\\", \\"bounds\\": \\"[)\\"}", '
'"dates_inner": null }, '
'"model": "postgres_tests.rangesmodel", "pk": null}]'
)