Fixed #27962 -- Allowed lookups on Area annotations.

This commit is contained in:
Sergey Fedoseev 2017-03-20 12:10:29 +05:00 committed by Tim Graham
parent e9149d3eb0
commit 1b1ea63f6a
2 changed files with 25 additions and 1 deletions

View File

@ -7,6 +7,7 @@ from decimal import Decimal
from django.contrib.gis.db.models.fields import GeoSelectFormatMixin from django.contrib.gis.db.models.fields import GeoSelectFormatMixin
from django.contrib.gis.geometry.backend import Geometry from django.contrib.gis.geometry.backend import Geometry
from django.contrib.gis.measure import Area, Distance from django.contrib.gis.measure import Area, Distance
from django.db import models
class BaseField: class BaseField:
@ -19,11 +20,21 @@ class BaseField:
return sql, params return sql, params
class AreaField(BaseField): class AreaField(models.FloatField):
"Wrapper for Area values." "Wrapper for Area values."
def __init__(self, area_att=None): def __init__(self, area_att=None):
self.area_att = area_att 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): def from_db_value(self, value, expression, connection, context):
if connection.features.interprets_empty_strings_as_nulls and value == '': if connection.features.interprets_empty_strings_as_nulls and value == '':
value = None value = None

View File

@ -264,6 +264,19 @@ class GISFunctionsTests(TestCase):
result = result.sq_m result = result.sq_m
self.assertAlmostEqual((result - c.mpoly.area) / c.mpoly.area, 0) 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") @skipUnlessDBFeature("has_MakeValid_function")
def test_make_valid(self): def test_make_valid(self):
invalid_geom = fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 1 1, 1 0, 0 0))') invalid_geom = fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 1 1, 1 0, 0 0))')