diff options
| author | Sergey Fedoseev <fedoseev.sergey@gmail.com> | 2017-03-20 12:10:29 +0500 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2017-03-23 20:06:16 -0400 |
| commit | 1b1ea63f6a4784e213c059c69beccaea20bc1a92 (patch) | |
| tree | 1eb5ea81c715e0bb198ff116ee329a11411144ca | |
| parent | e9149d3eb0ed0ddc8b27b1990eb2b7293c1231cd (diff) | |
Fixed #27962 -- Allowed lookups on Area annotations.
| -rw-r--r-- | django/contrib/gis/db/models/sql/conversion.py | 13 | ||||
| -rw-r--r-- | tests/gis_tests/geoapp/test_functions.py | 13 |
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))') |
