Fixed #27962 -- Allowed lookups on Area annotations.
This commit is contained in:
parent
e9149d3eb0
commit
1b1ea63f6a
|
@ -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
|
||||||
|
|
|
@ -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))')
|
||||||
|
|
Loading…
Reference in New Issue