summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Fedoseev <fedoseev.sergey@gmail.com>2017-03-20 12:10:29 +0500
committerTim Graham <timograham@gmail.com>2017-03-23 20:06:16 -0400
commit1b1ea63f6a4784e213c059c69beccaea20bc1a92 (patch)
tree1eb5ea81c715e0bb198ff116ee329a11411144ca
parente9149d3eb0ed0ddc8b27b1990eb2b7293c1231cd (diff)
Fixed #27962 -- Allowed lookups on Area annotations.
-rw-r--r--django/contrib/gis/db/models/sql/conversion.py13
-rw-r--r--tests/gis_tests/geoapp/test_functions.py13
2 files changed, 25 insertions, 1 deletions
diff --git a/django/contrib/gis/db/models/sql/conversion.py b/django/contrib/gis/db/models/sql/conversion.py
index ed414ca76e..299d39efdc 100644
--- a/django/contrib/gis/db/models/sql/conversion.py
+++ b/django/contrib/gis/db/models/sql/conversion.py
@@ -7,6 +7,7 @@ from decimal import Decimal
from django.contrib.gis.db.models.fields import GeoSelectFormatMixin
from django.contrib.gis.geometry.backend import Geometry
from django.contrib.gis.measure import Area, Distance
+from django.db import models
class BaseField:
@@ -19,11 +20,21 @@ class BaseField:
return sql, params
-class AreaField(BaseField):
+class AreaField(models.FloatField):
"Wrapper for Area values."
def __init__(self, area_att=None):
self.area_att = area_att
+ def get_prep_value(self, value):
+ if not isinstance(value, Area):
+ raise ValueError('AreaField only accepts Area measurement objects.')
+ return value
+
+ def get_db_prep_value(self, value, connection, prepared=False):
+ if value is None or not self.area_att:
+ return value
+ return getattr(value, self.area_att)
+
def from_db_value(self, value, expression, connection, context):
if connection.features.interprets_empty_strings_as_nulls and value == '':
value = None
diff --git a/tests/gis_tests/geoapp/test_functions.py b/tests/gis_tests/geoapp/test_functions.py
index 9896aff5c3..21b0c283e4 100644
--- a/tests/gis_tests/geoapp/test_functions.py
+++ b/tests/gis_tests/geoapp/test_functions.py
@@ -264,6 +264,19 @@ class GISFunctionsTests(TestCase):
result = result.sq_m
self.assertAlmostEqual((result - c.mpoly.area) / c.mpoly.area, 0)
+ @skipUnlessDBFeature("has_Area_function")
+ def test_area_lookups(self):
+ # Create projected countries so the test works on all backends.
+ CountryWebMercator.objects.bulk_create(
+ CountryWebMercator(name=c.name, mpoly=c.mpoly.transform(3857, clone=True))
+ for c in Country.objects.all()
+ )
+ qs = CountryWebMercator.objects.annotate(area=functions.Area('mpoly'))
+ self.assertEqual(qs.get(area__lt=Area(sq_km=500000)), CountryWebMercator.objects.get(name='New Zealand'))
+
+ with self.assertRaisesMessage(ValueError, 'AreaField only accepts Area measurement objects.'):
+ qs.get(area__lt=500000)
+
@skipUnlessDBFeature("has_MakeValid_function")
def test_make_valid(self):
invalid_geom = fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 1 1, 1 0, 0 0))')