summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHasan Ramezani <hasan.r67@gmail.com>2019-12-05 09:54:27 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-12-05 15:50:39 +0100
commit5d674eac871a306405b0fbbaeb17bbeba9c68bf3 (patch)
tree39f827b82af94b862d9e373d30fef52226e4bcdb
parent664521c56aa72e7749292e4b8d92f093421463b5 (diff)
Fixed #31039 -- Added support for contained_by lookup with AutoFields, SmallIntegerField, and DecimalField.
-rw-r--r--django/contrib/postgres/fields/ranges.py9
-rw-r--r--docs/ref/contrib/postgres/fields.txt16
-rw-r--r--docs/releases/3.1.txt7
-rw-r--r--tests/postgres_tests/migrations/0002_create_test_models.py16
-rw-r--r--tests/postgres_tests/models.py10
-rw-r--r--tests/postgres_tests/test_ranges.py62
6 files changed, 116 insertions, 4 deletions
diff --git a/django/contrib/postgres/fields/ranges.py b/django/contrib/postgres/fields/ranges.py
index b0b9275622..9a89fda02d 100644
--- a/django/contrib/postgres/fields/ranges.py
+++ b/django/contrib/postgres/fields/ranges.py
@@ -199,9 +199,11 @@ DateTimeRangeField.register_lookup(DateTimeRangeContains)
class RangeContainedBy(lookups.PostgresSimpleLookup):
lookup_name = 'contained_by'
type_mapping = {
+ 'smallint': 'int4range',
'integer': 'int4range',
'bigint': 'int8range',
'double precision': 'numrange',
+ 'numeric': 'numrange',
'date': 'daterange',
'timestamp with time zone': 'tstzrange',
}
@@ -209,13 +211,17 @@ class RangeContainedBy(lookups.PostgresSimpleLookup):
def process_rhs(self, compiler, connection):
rhs, rhs_params = super().process_rhs(compiler, connection)
- cast_type = self.type_mapping[self.lhs.output_field.db_type(connection)]
+ # Ignore precision for DecimalFields.
+ db_type = self.lhs.output_field.cast_db_type(connection).split('(')[0]
+ cast_type = self.type_mapping[db_type]
return '%s::%s' % (rhs, cast_type), rhs_params
def process_lhs(self, compiler, connection):
lhs, lhs_params = super().process_lhs(compiler, connection)
if isinstance(self.lhs.output_field, models.FloatField):
lhs = '%s::numeric' % lhs
+ elif isinstance(self.lhs.output_field, models.SmallIntegerField):
+ lhs = '%s::integer' % lhs
return lhs, lhs_params
def get_prep_lookup(self):
@@ -226,6 +232,7 @@ models.DateField.register_lookup(RangeContainedBy)
models.DateTimeField.register_lookup(RangeContainedBy)
models.IntegerField.register_lookup(RangeContainedBy)
models.FloatField.register_lookup(RangeContainedBy)
+models.DecimalField.register_lookup(RangeContainedBy)
@RangeField.register_lookup
diff --git a/docs/ref/contrib/postgres/fields.txt b/docs/ref/contrib/postgres/fields.txt
index cd35a33ee6..e8fcef6215 100644
--- a/docs/ref/contrib/postgres/fields.txt
+++ b/docs/ref/contrib/postgres/fields.txt
@@ -738,10 +738,14 @@ operators ``@>``, ``<@``, and ``&&`` respectively.
<QuerySet [<Event: Soft play>]>
The ``contained_by`` lookup is also available on the non-range field types:
+:class:`~django.db.models.SmallAutoField`,
+:class:`~django.db.models.AutoField`, :class:`~django.db.models.BigAutoField`,
+:class:`~django.db.models.SmallIntegerField`,
:class:`~django.db.models.IntegerField`,
:class:`~django.db.models.BigIntegerField`,
-:class:`~django.db.models.FloatField`, :class:`~django.db.models.DateField`,
-and :class:`~django.db.models.DateTimeField`. For example::
+:class:`~django.db.models.DecimalField`, :class:`~django.db.models.FloatField`,
+:class:`~django.db.models.DateField`, and
+:class:`~django.db.models.DateTimeField`. For example::
>>> from psycopg2.extras import DateTimeTZRange
>>> Event.objects.filter(start__contained_by=DateTimeTZRange(
@@ -750,6 +754,14 @@ and :class:`~django.db.models.DateTimeField`. For example::
... )
<QuerySet [<Event: Soft play>]>
+.. versionchanged:: 3.1
+
+ Support for :class:`~django.db.models.SmallAutoField`,
+ :class:`~django.db.models.AutoField`,
+ :class:`~django.db.models.BigAutoField`,
+ :class:`~django.db.models.SmallIntegerField`, and
+ :class:`~django.db.models.DecimalField` was added.
+
.. fieldlookup:: rangefield.overlap
``overlap``
diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt
index 631978d0ac..ec107bf29b 100644
--- a/docs/releases/3.1.txt
+++ b/docs/releases/3.1.txt
@@ -90,6 +90,13 @@ Minor features
:lookup:`rangefield.upper_inc`, and :lookup:`rangefield.upper_inf` allows
querying :class:`~django.contrib.postgres.fields.RangeField` by a bound type.
+* :lookup:`rangefield.contained_by` now supports
+ :class:`~django.db.models.SmallAutoField`,
+ :class:`~django.db.models.AutoField`,
+ :class:`~django.db.models.BigAutoField`,
+ :class:`~django.db.models.SmallIntegerField`, and
+ :class:`~django.db.models.DecimalField`.
+
:mod:`django.contrib.redirects`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/postgres_tests/migrations/0002_create_test_models.py b/tests/postgres_tests/migrations/0002_create_test_models.py
index 0e36cd1256..12d94e348a 100644
--- a/tests/postgres_tests/migrations/0002_create_test_models.py
+++ b/tests/postgres_tests/migrations/0002_create_test_models.py
@@ -125,6 +125,20 @@ class Migration(migrations.Migration):
bases=None,
),
migrations.CreateModel(
+ name='SmallAutoFieldModel',
+ fields=[
+ ('id', models.SmallAutoField(verbose_name='ID', serialize=False, primary_key=True)),
+ ],
+ options=None,
+ ),
+ migrations.CreateModel(
+ name='BigAutoFieldModel',
+ fields=[
+ ('id', models.BigAutoField(verbose_name='ID', serialize=False, primary_key=True)),
+ ],
+ options=None,
+ ),
+ migrations.CreateModel(
name='Scene',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
@@ -237,6 +251,8 @@ class Migration(migrations.Migration):
('float', models.FloatField(blank=True, null=True)),
('timestamp', models.DateTimeField(blank=True, null=True)),
('date', models.DateField(blank=True, null=True)),
+ ('small_integer', models.SmallIntegerField(blank=True, null=True)),
+ ('decimal_field', models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True)),
],
options={
'required_db_vendor': 'postgresql',
diff --git a/tests/postgres_tests/models.py b/tests/postgres_tests/models.py
index 2cf47b88c7..8528c59da1 100644
--- a/tests/postgres_tests/models.py
+++ b/tests/postgres_tests/models.py
@@ -93,6 +93,14 @@ class TextFieldModel(models.Model):
return self.field
+class SmallAutoFieldModel(models.Model):
+ id = models.SmallAutoField(primary_key=True)
+
+
+class BigAutoFieldModel(models.Model):
+ id = models.BigAutoField(primary_key=True)
+
+
# Scene/Character/Line models are used to test full text search. They're
# populated with content from Monty Python and the Holy Grail.
class Scene(models.Model):
@@ -148,6 +156,8 @@ class RangeLookupsModel(PostgreSQLModel):
float = models.FloatField(blank=True, null=True)
timestamp = models.DateTimeField(blank=True, null=True)
date = models.DateField(blank=True, null=True)
+ small_integer = models.SmallIntegerField(blank=True, null=True)
+ decimal_field = models.DecimalField(max_digits=5, decimal_places=2, blank=True, null=True)
class JSONModel(PostgreSQLModel):
diff --git a/tests/postgres_tests/test_ranges.py b/tests/postgres_tests/test_ranges.py
index 789ff3d546..7257d66505 100644
--- a/tests/postgres_tests/test_ranges.py
+++ b/tests/postgres_tests/test_ranges.py
@@ -11,7 +11,10 @@ from django.test.utils import isolate_apps
from django.utils import timezone
from . import PostgreSQLSimpleTestCase, PostgreSQLTestCase
-from .models import PostgreSQLModel, RangeLookupsModel, RangesModel
+from .models import (
+ BigAutoFieldModel, PostgreSQLModel, RangeLookupsModel, RangesModel,
+ SmallAutoFieldModel,
+)
try:
from psycopg2.extras import DateRange, DateTimeTZRange, NumericRange
@@ -354,6 +357,17 @@ class TestQueryingWithRanges(PostgreSQLTestCase):
[objs[0]],
)
+ def test_small_integer_field_contained_by(self):
+ objs = [
+ RangeLookupsModel.objects.create(small_integer=8),
+ RangeLookupsModel.objects.create(small_integer=4),
+ RangeLookupsModel.objects.create(small_integer=-1),
+ ]
+ self.assertSequenceEqual(
+ RangeLookupsModel.objects.filter(small_integer__contained_by=NumericRange(4, 6)),
+ [objs[1]],
+ )
+
def test_integer_range(self):
objs = [
RangeLookupsModel.objects.create(integer=5),
@@ -376,6 +390,19 @@ class TestQueryingWithRanges(PostgreSQLTestCase):
[objs[0]]
)
+ def test_decimal_field_contained_by(self):
+ objs = [
+ RangeLookupsModel.objects.create(decimal_field=Decimal('1.33')),
+ RangeLookupsModel.objects.create(decimal_field=Decimal('2.88')),
+ RangeLookupsModel.objects.create(decimal_field=Decimal('99.17')),
+ ]
+ self.assertSequenceEqual(
+ RangeLookupsModel.objects.filter(
+ decimal_field__contained_by=NumericRange(Decimal('1.89'), Decimal('7.91')),
+ ),
+ [objs[1]],
+ )
+
def test_float_range(self):
objs = [
RangeLookupsModel.objects.create(float=5),
@@ -387,6 +414,39 @@ class TestQueryingWithRanges(PostgreSQLTestCase):
[objs[0]]
)
+ def test_small_auto_field_contained_by(self):
+ objs = SmallAutoFieldModel.objects.bulk_create([
+ SmallAutoFieldModel() for i in range(1, 5)
+ ])
+ self.assertSequenceEqual(
+ SmallAutoFieldModel.objects.filter(
+ id__contained_by=NumericRange(objs[1].pk, objs[3].pk),
+ ),
+ objs[1:3],
+ )
+
+ def test_auto_field_contained_by(self):
+ objs = RangeLookupsModel.objects.bulk_create([
+ RangeLookupsModel() for i in range(1, 5)
+ ])
+ self.assertSequenceEqual(
+ RangeLookupsModel.objects.filter(
+ id__contained_by=NumericRange(objs[1].pk, objs[3].pk),
+ ),
+ objs[1:3],
+ )
+
+ def test_big_auto_field_contained_by(self):
+ objs = BigAutoFieldModel.objects.bulk_create([
+ BigAutoFieldModel() for i in range(1, 5)
+ ])
+ self.assertSequenceEqual(
+ BigAutoFieldModel.objects.filter(
+ id__contained_by=NumericRange(objs[1].pk, objs[3].pk),
+ ),
+ objs[1:3],
+ )
+
def test_f_ranges(self):
parent = RangesModel.objects.create(decimals=NumericRange(0, 10))
objs = [