mirror of
https://github.com/django/django.git
synced 2025-07-04 17:59:13 +00:00
gis: (1) fixed WKT admin bug
(2) cleaned up GeometryField (moved SQL creation into field, index creation now on by default) (3) now have exact lookup type, e.g., filter(geom='...') works git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@5336 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
58aa35e7a5
commit
f84bb1b18f
@ -1,60 +1,78 @@
|
|||||||
# The Django base Field class.
|
# The Django base Field class.
|
||||||
from django.db.models.fields import Field
|
from django.db.models.fields import Field
|
||||||
from django.contrib.gis.db.models.postgis import POSTGIS_TERMS
|
from django.contrib.gis.db.models.postgis import POSTGIS_TERMS, quotename
|
||||||
from django.contrib.gis.oldforms import WKTField
|
from django.contrib.gis.oldforms import WKTField
|
||||||
from django.utils.functional import curry
|
from django.utils.functional import curry
|
||||||
|
from django.contrib.gis.geos import GEOSGeometry, GEOSException
|
||||||
#TODO: add db.quotename.
|
|
||||||
|
|
||||||
# Creates the SQL to add the model to the database.
|
|
||||||
def _add_geom(geom, srid, style, model, field, dim=2):
|
|
||||||
# Constructing the AddGeometryColumn(...) command -- the style
|
|
||||||
# object is passed in from the management module and is used
|
|
||||||
# to syntax highlight the command for 'sqlall'
|
|
||||||
sql = style.SQL_KEYWORD('SELECT ') + \
|
|
||||||
style.SQL_TABLE('AddGeometryColumn') + "('" + \
|
|
||||||
style.SQL_TABLE(model) + "', '" + \
|
|
||||||
style.SQL_FIELD(field) + "', " + \
|
|
||||||
style.SQL_FIELD(str(srid)) + ", '" + \
|
|
||||||
style.SQL_COLTYPE(geom) + "', " + \
|
|
||||||
style.SQL_KEYWORD(str(dim)) + \
|
|
||||||
');'
|
|
||||||
return sql
|
|
||||||
|
|
||||||
# Creates an index for the given geometry.
|
|
||||||
def _geom_index(geom, style, model, field,
|
|
||||||
index_type='GIST',
|
|
||||||
index_opts='GIST_GEOMETRY_OPS'):
|
|
||||||
sql = style.SQL_KEYWORD('CREATE INDEX ') + \
|
|
||||||
style.SQL_TABLE('"%s_%s_id"' % (model, field)) + \
|
|
||||||
style.SQL_KEYWORD(' ON ') + \
|
|
||||||
style.SQL_TABLE('"%s"' % model) + \
|
|
||||||
style.SQL_KEYWORD(' USING ') + \
|
|
||||||
style.SQL_COLTYPE(index_type) + ' ( ' + \
|
|
||||||
style.SQL_FIELD('"%s"' % field) + ' ' + \
|
|
||||||
style.SQL_KEYWORD(index_opts) + ' );'
|
|
||||||
return sql
|
|
||||||
|
|
||||||
class GeometryField(Field):
|
class GeometryField(Field):
|
||||||
"The base GIS field -- maps to the OpenGIS Geometry type."
|
"The base GIS field -- maps to the OpenGIS Specification Geometry type."
|
||||||
|
|
||||||
# The OpenGIS Geometry name.
|
# The OpenGIS Geometry name.
|
||||||
_geom = 'GEOMETRY'
|
_geom = 'GEOMETRY'
|
||||||
|
|
||||||
def __init__(self, srid=4326, index=False, **kwargs):
|
def __init__(self, srid=4326, index=True, dim=2, **kwargs):
|
||||||
#TODO: SRID a standard, or specific to postgis?
|
"""The initialization function for geometry fields. Takes the following
|
||||||
# Whether or not index this field, defaults to False
|
as keyword arguments:
|
||||||
# Why can't we just use db_index?
|
|
||||||
# TODO: Move index creation (and kwarg lookup, and...)
|
srid - The spatial reference system identifier. An OGC standard.
|
||||||
# into Field rather than core.management and db.models.query.
|
Defaults to 4326 (WGS84)
|
||||||
|
|
||||||
|
index - Indicates whether to create a GiST index. Defaults to True.
|
||||||
|
Set this instead of 'db_index' for geographic fields since index
|
||||||
|
creation is different for geometry columns.
|
||||||
|
|
||||||
|
dim - The number of dimensions for this geometry. Defaults to 2.
|
||||||
|
"""
|
||||||
self._index = index
|
self._index = index
|
||||||
|
|
||||||
# The SRID for the geometry, defaults to 4326.
|
|
||||||
self._srid = srid
|
self._srid = srid
|
||||||
|
self._dim = dim
|
||||||
|
super(GeometryField, self).__init__(**kwargs) # Calling the parent initializtion function
|
||||||
|
|
||||||
# Calling the Field initialization function first
|
def _add_geom(self, style, db_table, field):
|
||||||
super(GeometryField, self).__init__(**kwargs)
|
"""Constructs the addition of the geometry to the table using the
|
||||||
|
AddGeometryColumn(...) PostGIS (and OGC standard) function.
|
||||||
|
|
||||||
|
Takes the style object (provides syntax highlighting) as well as the
|
||||||
|
database table and field. The dimensions can be specified via
|
||||||
|
the dim keyword as well.
|
||||||
|
"""
|
||||||
|
sql = style.SQL_KEYWORD('SELECT ') + \
|
||||||
|
style.SQL_TABLE('AddGeometryColumn') + '(' + \
|
||||||
|
style.SQL_TABLE(quotename(db_table)) + ', ' + \
|
||||||
|
style.SQL_FIELD(quotename(field)) + ', ' + \
|
||||||
|
style.SQL_FIELD(str(self._srid)) + ', ' + \
|
||||||
|
style.SQL_COLTYPE(quotename(self._geom)) + ', ' + \
|
||||||
|
style.SQL_KEYWORD(str(self._dim)) + ');'
|
||||||
|
return sql
|
||||||
|
|
||||||
|
def _geom_index(self, style, db_table, field,
|
||||||
|
index_type='GIST', index_opts='GIST_GEOMETRY_OPS'):
|
||||||
|
"Creates a GiST index for this geometry field."
|
||||||
|
sql = style.SQL_KEYWORD('CREATE INDEX ') + \
|
||||||
|
style.SQL_TABLE(quotename('%s_%s_id' % (db_table, field), dbl=True)) + \
|
||||||
|
style.SQL_KEYWORD(' ON ') + \
|
||||||
|
style.SQL_TABLE(quotename(db_table, dbl=True)) + \
|
||||||
|
style.SQL_KEYWORD(' USING ') + \
|
||||||
|
style.SQL_COLTYPE(index_type) + ' ( ' + \
|
||||||
|
style.SQL_FIELD(quotename(field, dbl=True)) + ' ' + \
|
||||||
|
style.SQL_KEYWORD(index_opts) + ' );'
|
||||||
|
return sql
|
||||||
|
|
||||||
|
def _post_create_sql(self, style, db_table, field):
|
||||||
|
"""Returns SQL that will be executed after the model has been
|
||||||
|
created. Geometry columns must be added after creation with the
|
||||||
|
PostGIS AddGeometryColumn() function."""
|
||||||
|
|
||||||
|
# Getting the AddGeometryColumn() SQL necessary to create a PostGIS
|
||||||
|
# geometry field.
|
||||||
|
post_sql = self._add_geom(style, db_table, field)
|
||||||
|
|
||||||
|
# If the user wants to index this data, then get the indexing SQL as well.
|
||||||
|
if self._index:
|
||||||
|
return '%s\n%s' % (post_sql, self._geom_index(style, db_table, field))
|
||||||
|
else:
|
||||||
|
return post_sql
|
||||||
|
|
||||||
def contribute_to_class(self, cls, name):
|
def contribute_to_class(self, cls, name):
|
||||||
super(GeometryField, self).contribute_to_class(cls, name)
|
super(GeometryField, self).contribute_to_class(cls, name)
|
||||||
@ -68,22 +86,6 @@ class GeometryField(Field):
|
|||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "NoField"
|
return "NoField"
|
||||||
|
|
||||||
def _post_create_sql(self, *args, **kwargs):
|
|
||||||
"""Returns SQL that will be executed after the model has been created. Geometry
|
|
||||||
columns must be added after creation with the PostGIS AddGeometryColumn() function."""
|
|
||||||
|
|
||||||
#TODO: clean up *args/**kwargs.
|
|
||||||
|
|
||||||
# Getting the AddGeometryColumn() SQL necessary to create a PostGIS
|
|
||||||
# geometry field.
|
|
||||||
post_sql = _add_geom(self._geom, self._srid, *args, **kwargs)
|
|
||||||
|
|
||||||
# If the user wants to index this data, then get the indexing SQL as well.
|
|
||||||
if self._index:
|
|
||||||
return '%s\n%s' % (post_sql, _geom_index(self._geom, *args, **kwargs))
|
|
||||||
else:
|
|
||||||
return post_sql
|
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value):
|
def get_db_prep_lookup(self, lookup_type, value):
|
||||||
"""Returns field's value prepared for database lookup; the SRID of the geometry is
|
"""Returns field's value prepared for database lookup; the SRID of the geometry is
|
||||||
included by default in these queries."""
|
included by default in these queries."""
|
||||||
|
@ -27,6 +27,7 @@ POSTGIS_OPERATORS = {
|
|||||||
# The "~=" operator is the "same as" operator. It tests actual geometric equality of two features. So if
|
# The "~=" operator is the "same as" operator. It tests actual geometric equality of two features. So if
|
||||||
# A and B are the same feature, vertex-by-vertex, the operator returns true.
|
# A and B are the same feature, vertex-by-vertex, the operator returns true.
|
||||||
'same_as' : '~= %s',
|
'same_as' : '~= %s',
|
||||||
|
'exact' : '~= %s',
|
||||||
# The "@" operator returns true if A's bounding box is completely contained by B's bounding box.
|
# The "@" operator returns true if A's bounding box is completely contained by B's bounding box.
|
||||||
'contained' : '@ %s',
|
'contained' : '@ %s',
|
||||||
# The "~" operator returns true if A's bounding box completely contains B's bounding box.
|
# The "~" operator returns true if A's bounding box completely contains B's bounding box.
|
||||||
@ -50,6 +51,11 @@ POSTGIS_GEOMETRY_FUNCTIONS = {
|
|||||||
'relate' : 'Relate',
|
'relate' : 'Relate',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The quotation used for postgis (uses single quotes).
|
||||||
|
def quotename(value, dbl=False):
|
||||||
|
if dbl: return '"%s"' % value
|
||||||
|
else: return "'%s'" % value
|
||||||
|
|
||||||
# These are the PostGIS-customized QUERY_TERMS, combines both the operators
|
# These are the PostGIS-customized QUERY_TERMS, combines both the operators
|
||||||
# and the geometry functions.
|
# and the geometry functions.
|
||||||
POSTGIS_TERMS = list(POSTGIS_OPERATORS.keys()) # Getting the operators first
|
POSTGIS_TERMS = list(POSTGIS_OPERATORS.keys()) # Getting the operators first
|
||||||
|
@ -6,7 +6,11 @@ class WKTField(LargeTextField):
|
|||||||
|
|
||||||
def render(self, data):
|
def render(self, data):
|
||||||
# PostGIS uses EWKBHEX to store its values internally, converting
|
# PostGIS uses EWKBHEX to store its values internally, converting
|
||||||
# to WKT for the admin first.
|
# to WKT for the admin first -- unless there's no data, then just
|
||||||
return super(WKTField, self).render(hex_to_wkt(data))
|
# pass None to LargeTextField's render.
|
||||||
|
if not data:
|
||||||
|
return super(WKTField, self).render(None)
|
||||||
|
else:
|
||||||
|
return super(WKTField, self).render(hex_to_wkt(data))
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user