You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
64 lines
2.9 KiB
64 lines
2.9 KiB
import datetime |
|
from django.db.models.fields import Field |
|
from django.db.models.sql.where import WhereNode |
|
from django.contrib.gis.db.backend import get_geo_where_clause, SpatialBackend |
|
|
|
class GeoAnnotation(object): |
|
""" |
|
The annotation used for GeometryFields; basically a placeholder |
|
for metadata needed by the `get_geo_where_clause` of the spatial |
|
backend. |
|
""" |
|
def __init__(self, field, value, where): |
|
self.geodetic = field.geodetic |
|
self.geom_type = field._geom |
|
self.value = value |
|
self.where = tuple(where) |
|
|
|
class GeoWhereNode(WhereNode): |
|
""" |
|
Used to represent the SQL where-clause for spatial databases -- |
|
these are tied to the GeoQuery class that created it. |
|
""" |
|
def add(self, data, connector): |
|
""" |
|
This is overridden from the regular WhereNode to handle the |
|
peculiarties of GeometryFields, because they need a special |
|
annotation object that contains the spatial metadata from the |
|
field to generate the spatial SQL. |
|
""" |
|
if not isinstance(data, (list, tuple)): |
|
return super(WhereNode, self).add(data, connector) |
|
alias, col, field, lookup_type, value = data |
|
if not hasattr(field, "_geom"): |
|
# Not a geographic field, so call `WhereNode.add`. |
|
return super(GeoWhereNode, self).add(data, connector) |
|
else: |
|
# `GeometryField.get_db_prep_lookup` returns a where clause |
|
# substitution array in addition to the parameters. |
|
where, params = field.get_db_prep_lookup(lookup_type, value) |
|
|
|
# The annotation will be a `GeoAnnotation` object that |
|
# will contain the necessary geometry field metadata for |
|
# the `get_geo_where_clause` to construct the appropriate |
|
# spatial SQL when `make_atom` is called. |
|
annotation = GeoAnnotation(field, value, where) |
|
return super(WhereNode, self).add((alias, col, field.db_type(), lookup_type, |
|
annotation, params), connector) |
|
|
|
def make_atom(self, child, qn): |
|
table_alias, name, db_type, lookup_type, value_annot, params = child |
|
|
|
if isinstance(value_annot, GeoAnnotation): |
|
if lookup_type in SpatialBackend.gis_terms: |
|
# Getting the geographic where clause; substitution parameters |
|
# will be populated in the GeoFieldSQL object returned by the |
|
# GeometryField. |
|
gwc = get_geo_where_clause(table_alias, name, lookup_type, value_annot) |
|
return gwc % value_annot.where, params |
|
else: |
|
raise TypeError('Invalid lookup type: %r' % lookup_type) |
|
else: |
|
# If not a GeometryField, call the `make_atom` from the |
|
# base class. |
|
return super(GeoWhereNode, self).make_atom(child, qn)
|
|
|