Refs #27736 -- Used decorators for GIS lookup registration.

This commit is contained in:
Sergey Fedoseev 2017-03-25 22:55:59 +05:00
parent 7fffe3acc2
commit 378cf689d8
4 changed files with 39 additions and 109 deletions

View File

@ -1,5 +1,6 @@
from django.db.models import * # NOQA isort:skip from django.db.models import * # NOQA isort:skip
from django.db.models import __all__ as models_all # isort:skip from django.db.models import __all__ as models_all # isort:skip
import django.contrib.gis.db.models.lookups # NOQA
from django.contrib.gis.db.models.aggregates import * # NOQA from django.contrib.gis.db.models.aggregates import * # NOQA
from django.contrib.gis.db.models.aggregates import __all__ as aggregates_all from django.contrib.gis.db.models.aggregates import __all__ as aggregates_all
from django.contrib.gis.db.models.fields import ( from django.contrib.gis.db.models.fields import (

View File

@ -1,9 +1,6 @@
from collections import defaultdict from collections import defaultdict
from django.contrib.gis import forms, gdal from django.contrib.gis import forms, gdal
from django.contrib.gis.db.models.lookups import (
RasterBandTransform, gis_lookups,
)
from django.contrib.gis.db.models.proxy import SpatialProxy from django.contrib.gis.db.models.proxy import SpatialProxy
from django.contrib.gis.gdal.error import GDALException from django.contrib.gis.gdal.error import GDALException
from django.contrib.gis.geometry.backend import Geometry, GeometryException from django.contrib.gis.geometry.backend import Geometry, GeometryException
@ -243,10 +240,6 @@ class BaseSpatialField(Field):
return obj return obj
for klass in gis_lookups.values():
BaseSpatialField.register_lookup(klass)
class GeometryField(GeoSelectFormatMixin, BaseSpatialField): class GeometryField(GeoSelectFormatMixin, BaseSpatialField):
""" """
The base Geometry field -- maps to the OpenGIS Specification Geometry type. The base Geometry field -- maps to the OpenGIS Specification Geometry type.
@ -429,6 +422,7 @@ class RasterField(BaseSpatialField):
setattr(cls, self.attname, SpatialProxy(gdal.GDALRaster, self)) setattr(cls, self.attname, SpatialProxy(gdal.GDALRaster, self))
def get_transform(self, name): def get_transform(self, name):
from django.contrib.gis.db.models.lookups import RasterBandTransform
try: try:
band_index = int(name) band_index = int(name)
return type( return type(

View File

@ -1,11 +1,10 @@
import re import re
from django.contrib.gis.db.models.fields import BaseSpatialField
from django.db.models.expressions import Col, Expression from django.db.models.expressions import Col, Expression
from django.db.models.lookups import Lookup, Transform from django.db.models.lookups import Lookup, Transform
from django.db.models.sql.query import Query from django.db.models.sql.query import Query
gis_lookups = {}
class RasterBandTransform(Transform): class RasterBandTransform(Transform):
def as_sql(self, compiler, connection): def as_sql(self, compiler, connection):
@ -107,6 +106,7 @@ class GISLookup(Lookup):
# Geometry operators # Geometry operators
# ------------------ # ------------------
@BaseSpatialField.register_lookup
class OverlapsLeftLookup(GISLookup): class OverlapsLeftLookup(GISLookup):
""" """
The overlaps_left operator returns true if A's bounding box overlaps or is to the The overlaps_left operator returns true if A's bounding box overlaps or is to the
@ -115,9 +115,7 @@ class OverlapsLeftLookup(GISLookup):
lookup_name = 'overlaps_left' lookup_name = 'overlaps_left'
gis_lookups['overlaps_left'] = OverlapsLeftLookup @BaseSpatialField.register_lookup
class OverlapsRightLookup(GISLookup): class OverlapsRightLookup(GISLookup):
""" """
The 'overlaps_right' operator returns true if A's bounding box overlaps or is to the The 'overlaps_right' operator returns true if A's bounding box overlaps or is to the
@ -126,9 +124,7 @@ class OverlapsRightLookup(GISLookup):
lookup_name = 'overlaps_right' lookup_name = 'overlaps_right'
gis_lookups['overlaps_right'] = OverlapsRightLookup @BaseSpatialField.register_lookup
class OverlapsBelowLookup(GISLookup): class OverlapsBelowLookup(GISLookup):
""" """
The 'overlaps_below' operator returns true if A's bounding box overlaps or is below The 'overlaps_below' operator returns true if A's bounding box overlaps or is below
@ -137,9 +133,7 @@ class OverlapsBelowLookup(GISLookup):
lookup_name = 'overlaps_below' lookup_name = 'overlaps_below'
gis_lookups['overlaps_below'] = OverlapsBelowLookup @BaseSpatialField.register_lookup
class OverlapsAboveLookup(GISLookup): class OverlapsAboveLookup(GISLookup):
""" """
The 'overlaps_above' operator returns true if A's bounding box overlaps or is above The 'overlaps_above' operator returns true if A's bounding box overlaps or is above
@ -148,9 +142,7 @@ class OverlapsAboveLookup(GISLookup):
lookup_name = 'overlaps_above' lookup_name = 'overlaps_above'
gis_lookups['overlaps_above'] = OverlapsAboveLookup @BaseSpatialField.register_lookup
class LeftLookup(GISLookup): class LeftLookup(GISLookup):
""" """
The 'left' operator returns true if A's bounding box is strictly to the left The 'left' operator returns true if A's bounding box is strictly to the left
@ -159,9 +151,7 @@ class LeftLookup(GISLookup):
lookup_name = 'left' lookup_name = 'left'
gis_lookups['left'] = LeftLookup @BaseSpatialField.register_lookup
class RightLookup(GISLookup): class RightLookup(GISLookup):
""" """
The 'right' operator returns true if A's bounding box is strictly to the right The 'right' operator returns true if A's bounding box is strictly to the right
@ -170,9 +160,7 @@ class RightLookup(GISLookup):
lookup_name = 'right' lookup_name = 'right'
gis_lookups['right'] = RightLookup @BaseSpatialField.register_lookup
class StrictlyBelowLookup(GISLookup): class StrictlyBelowLookup(GISLookup):
""" """
The 'strictly_below' operator returns true if A's bounding box is strictly below B's The 'strictly_below' operator returns true if A's bounding box is strictly below B's
@ -181,9 +169,7 @@ class StrictlyBelowLookup(GISLookup):
lookup_name = 'strictly_below' lookup_name = 'strictly_below'
gis_lookups['strictly_below'] = StrictlyBelowLookup @BaseSpatialField.register_lookup
class StrictlyAboveLookup(GISLookup): class StrictlyAboveLookup(GISLookup):
""" """
The 'strictly_above' operator returns true if A's bounding box is strictly above B's The 'strictly_above' operator returns true if A's bounding box is strictly above B's
@ -192,9 +178,7 @@ class StrictlyAboveLookup(GISLookup):
lookup_name = 'strictly_above' lookup_name = 'strictly_above'
gis_lookups['strictly_above'] = StrictlyAboveLookup @BaseSpatialField.register_lookup
class SameAsLookup(GISLookup): class SameAsLookup(GISLookup):
""" """
The "~=" operator is the "same as" operator. It tests actual geometric The "~=" operator is the "same as" operator. It tests actual geometric
@ -204,17 +188,10 @@ class SameAsLookup(GISLookup):
lookup_name = 'same_as' lookup_name = 'same_as'
gis_lookups['same_as'] = SameAsLookup BaseSpatialField.register_lookup(SameAsLookup, 'exact')
class ExactLookup(SameAsLookup):
# Alias of same_as
lookup_name = 'exact'
gis_lookups['exact'] = ExactLookup
@BaseSpatialField.register_lookup
class BBContainsLookup(GISLookup): class BBContainsLookup(GISLookup):
""" """
The 'bbcontains' operator returns true if A's bounding box completely contains The 'bbcontains' operator returns true if A's bounding box completely contains
@ -223,9 +200,7 @@ class BBContainsLookup(GISLookup):
lookup_name = 'bbcontains' lookup_name = 'bbcontains'
gis_lookups['bbcontains'] = BBContainsLookup @BaseSpatialField.register_lookup
class BBOverlapsLookup(GISLookup): class BBOverlapsLookup(GISLookup):
""" """
The 'bboverlaps' operator returns true if A's bounding box overlaps B's bounding box. The 'bboverlaps' operator returns true if A's bounding box overlaps B's bounding box.
@ -233,9 +208,7 @@ class BBOverlapsLookup(GISLookup):
lookup_name = 'bboverlaps' lookup_name = 'bboverlaps'
gis_lookups['bboverlaps'] = BBOverlapsLookup @BaseSpatialField.register_lookup
class ContainedLookup(GISLookup): class ContainedLookup(GISLookup):
""" """
The 'contained' operator returns true if A's bounding box is completely contained The 'contained' operator returns true if A's bounding box is completely contained
@ -244,69 +217,51 @@ class ContainedLookup(GISLookup):
lookup_name = 'contained' lookup_name = 'contained'
gis_lookups['contained'] = ContainedLookup
# ------------------ # ------------------
# Geometry functions # Geometry functions
# ------------------ # ------------------
@BaseSpatialField.register_lookup
class ContainsLookup(GISLookup): class ContainsLookup(GISLookup):
lookup_name = 'contains' lookup_name = 'contains'
gis_lookups['contains'] = ContainsLookup @BaseSpatialField.register_lookup
class ContainsProperlyLookup(GISLookup): class ContainsProperlyLookup(GISLookup):
lookup_name = 'contains_properly' lookup_name = 'contains_properly'
gis_lookups['contains_properly'] = ContainsProperlyLookup @BaseSpatialField.register_lookup
class CoveredByLookup(GISLookup): class CoveredByLookup(GISLookup):
lookup_name = 'coveredby' lookup_name = 'coveredby'
gis_lookups['coveredby'] = CoveredByLookup @BaseSpatialField.register_lookup
class CoversLookup(GISLookup): class CoversLookup(GISLookup):
lookup_name = 'covers' lookup_name = 'covers'
gis_lookups['covers'] = CoversLookup @BaseSpatialField.register_lookup
class CrossesLookup(GISLookup): class CrossesLookup(GISLookup):
lookup_name = 'crosses' lookup_name = 'crosses'
gis_lookups['crosses'] = CrossesLookup @BaseSpatialField.register_lookup
class DisjointLookup(GISLookup): class DisjointLookup(GISLookup):
lookup_name = 'disjoint' lookup_name = 'disjoint'
gis_lookups['disjoint'] = DisjointLookup @BaseSpatialField.register_lookup
class EqualsLookup(GISLookup): class EqualsLookup(GISLookup):
lookup_name = 'equals' lookup_name = 'equals'
gis_lookups['equals'] = EqualsLookup @BaseSpatialField.register_lookup
class IntersectsLookup(GISLookup): class IntersectsLookup(GISLookup):
lookup_name = 'intersects' lookup_name = 'intersects'
gis_lookups['intersects'] = IntersectsLookup @BaseSpatialField.register_lookup
class IsValidLookup(GISLookup): class IsValidLookup(GISLookup):
lookup_name = 'isvalid' lookup_name = 'isvalid'
sql_template = '%(func)s(%(lhs)s)' sql_template = '%(func)s(%(lhs)s)'
@ -322,16 +277,12 @@ class IsValidLookup(GISLookup):
return sql, params return sql, params
gis_lookups['isvalid'] = IsValidLookup @BaseSpatialField.register_lookup
class OverlapsLookup(GISLookup): class OverlapsLookup(GISLookup):
lookup_name = 'overlaps' lookup_name = 'overlaps'
gis_lookups['overlaps'] = OverlapsLookup @BaseSpatialField.register_lookup
class RelateLookup(GISLookup): class RelateLookup(GISLookup):
lookup_name = 'relate' lookup_name = 'relate'
sql_template = '%(func)s(%(lhs)s, %(rhs)s, %%s)' sql_template = '%(func)s(%(lhs)s, %(rhs)s, %%s)'
@ -351,23 +302,16 @@ class RelateLookup(GISLookup):
return super().get_db_prep_lookup(value, connection) return super().get_db_prep_lookup(value, connection)
gis_lookups['relate'] = RelateLookup @BaseSpatialField.register_lookup
class TouchesLookup(GISLookup): class TouchesLookup(GISLookup):
lookup_name = 'touches' lookup_name = 'touches'
gis_lookups['touches'] = TouchesLookup @BaseSpatialField.register_lookup
class WithinLookup(GISLookup): class WithinLookup(GISLookup):
lookup_name = 'within' lookup_name = 'within'
gis_lookups['within'] = WithinLookup
class DistanceLookupBase(GISLookup): class DistanceLookupBase(GISLookup):
distance = True distance = True
sql_template = '%(func)s(%(lhs)s, %(rhs)s) %(op)s %(value)s' sql_template = '%(func)s(%(lhs)s, %(rhs)s) %(op)s %(value)s'
@ -400,37 +344,27 @@ class DistanceLookupBase(GISLookup):
return (rhs, params) return (rhs, params)
@BaseSpatialField.register_lookup
class DWithinLookup(DistanceLookupBase): class DWithinLookup(DistanceLookupBase):
lookup_name = 'dwithin' lookup_name = 'dwithin'
sql_template = '%(func)s(%(lhs)s, %(rhs)s, %%s)' sql_template = '%(func)s(%(lhs)s, %(rhs)s, %%s)'
gis_lookups['dwithin'] = DWithinLookup @BaseSpatialField.register_lookup
class DistanceGTLookup(DistanceLookupBase): class DistanceGTLookup(DistanceLookupBase):
lookup_name = 'distance_gt' lookup_name = 'distance_gt'
gis_lookups['distance_gt'] = DistanceGTLookup @BaseSpatialField.register_lookup
class DistanceGTELookup(DistanceLookupBase): class DistanceGTELookup(DistanceLookupBase):
lookup_name = 'distance_gte' lookup_name = 'distance_gte'
gis_lookups['distance_gte'] = DistanceGTELookup @BaseSpatialField.register_lookup
class DistanceLTLookup(DistanceLookupBase): class DistanceLTLookup(DistanceLookupBase):
lookup_name = 'distance_lt' lookup_name = 'distance_lt'
gis_lookups['distance_lt'] = DistanceLTLookup @BaseSpatialField.register_lookup
class DistanceLTELookup(DistanceLookupBase): class DistanceLTELookup(DistanceLookupBase):
lookup_name = 'distance_lte' lookup_name = 'distance_lte'
gis_lookups['distance_lte'] = DistanceLTELookup

View File

@ -1,9 +1,8 @@
import json import json
from django.contrib.gis.db.models.fields import BaseSpatialField
from django.contrib.gis.db.models.functions import Distance from django.contrib.gis.db.models.functions import Distance
from django.contrib.gis.db.models.lookups import ( from django.contrib.gis.db.models.lookups import DistanceLookupBase, GISLookup
DistanceLookupBase, gis_lookups,
)
from django.contrib.gis.gdal import HAS_GDAL from django.contrib.gis.gdal import HAS_GDAL
from django.contrib.gis.geos import GEOSGeometry from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis.measure import D from django.contrib.gis.measure import D
@ -130,7 +129,9 @@ class RasterFieldTest(TransactionTestCase):
stx_pnt.transform(3086) stx_pnt.transform(3086)
# Loop through all the GIS lookups. # Loop through all the GIS lookups.
for name, lookup in gis_lookups.items(): for name, lookup in BaseSpatialField.get_lookups().items():
if not isinstance(lookup, GISLookup):
continue
# Construct lookup filter strings. # Construct lookup filter strings.
combo_keys = [ combo_keys = [
field + name for field in [ field + name for field in [