1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

gis: From jbronn:

Renamed LineString to LineStringField.
Changed qs kwargs format, e.g. overlapsleft -> overlaps_left.
Added oldforms WKTField, allowing read-only viewing of Geom fields (for people that know Well-Known Text).
Index creation working for common case.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@4851 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jeremy Dunck 2007-03-29 16:51:20 +00:00
parent 8fe2413527
commit 177a49ae5e
3 changed files with 49 additions and 22 deletions

View File

@ -6,7 +6,7 @@ from django.contrib.gis.db.models.manager import GeoManager
# The various PostGIS/OpenGIS enabled fields. # The various PostGIS/OpenGIS enabled fields.
from django.contrib.gis.db.models.fields import \ from django.contrib.gis.db.models.fields import \
GeometryField, PointField, LineString, PolygonField, \ GeometryField, PointField, LineStringField, PolygonField, \
MultiPointField, MultiLineStringField, MultiPolygonField, \ MultiPointField, MultiLineStringField, MultiPolygonField, \
GeometryCollectionField GeometryCollectionField

View File

@ -1,6 +1,10 @@
# 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.oldforms import LargeTextField
from django.contrib.gis.db.models.postgis import POSTGIS_TERMS from django.contrib.gis.db.models.postgis import POSTGIS_TERMS
from geos import geomToWKT, geomFromHEX
#TODO: add db.quotename.
# Creates the SQL to add the model to the database. # Creates the SQL to add the model to the database.
def _add_geom(geom, srid, style, model, field, dim=2): def _add_geom(geom, srid, style, model, field, dim=2):
@ -20,17 +24,26 @@ def _add_geom(geom, srid, style, model, field, dim=2):
# Creates an index for the given geometry. # Creates an index for the given geometry.
def _geom_index(geom, style, model, field, def _geom_index(geom, style, model, field,
index_type='GIST', index_type='GIST',
index_opts='GIST_GEOMETRY_OPTS'): index_opts='GIST_GEOMETRY_OPS'):
sql = style.SQL_KEYWORD('CREATE INDEX ') + \ sql = style.SQL_KEYWORD('CREATE INDEX ') + \
style.SQL_FIELD(field + '_idx') + \ style.SQL_TABLE('"%s_%s_id"' % (model, field)) + \
style.SQL_KEYWORD(' ON ') + \ style.SQL_KEYWORD(' ON ') + \
style.SQL_TABLE(model) + \ style.SQL_TABLE('"%s"' % model) + \
style.SQL_KEYWORD(' USING ') + \ style.SQL_KEYWORD(' USING ') + \
style.SQL_COLTYPE(index_type) + ' ( ' + \ style.SQL_COLTYPE(index_type) + ' ( ' + \
style.SQL_FIELD(field) + ' ' + \ style.SQL_FIELD('"%s"' % field) + ' ' + \
style.SQL_KEYWORD(index_opts) + ' );' style.SQL_KEYWORD(index_opts) + ' );'
return sql return sql
class WKTField(LargeTextField):
"An oldforms LargeTextField for editing WKT text in the admin."
def render(self, data):
# PostGIS uses EWKBHEX to store its values internally, converting
# to WKT for the admin first.
wkt = geomToWKT(geomFromHEX(data))
return super(WKTField, self).render(wkt)
class GeometryField(Field): class GeometryField(Field):
"The base GIS field -- maps to the OpenGIS Geometry type." "The base GIS field -- maps to the OpenGIS Geometry type."
@ -38,12 +51,19 @@ class GeometryField(Field):
_geom = 'GEOMETRY' _geom = 'GEOMETRY'
def __init__(self, srid=4326, index=False, **kwargs): def __init__(self, srid=4326, index=False, **kwargs):
#TODO: SRID a standard, or specific to postgis?
# Whether or not index this field, defaults to False
# Why can't we just use db_index?
# TODO: Move index creation (and kwarg lookup, and...)
# into Field rather than core.management and db.models.query.
self._index = index
# The SRID for the geometry, defaults to 4326.
self._srid = srid
# Calling the Field initialization function first # Calling the Field initialization function first
super(GeometryField, self).__init__(**kwargs) super(GeometryField, self).__init__(**kwargs)
# The SRID for the geometry, defaults to 4326
self._srid = srid
self._index = index
def get_internal_type(self): def get_internal_type(self):
return "NoField" return "NoField"
@ -51,11 +71,16 @@ class GeometryField(Field):
def _post_create_sql(self, *args, **kwargs): def _post_create_sql(self, *args, **kwargs):
"""Returns SQL that will be executed after the model has been created. Geometry """Returns SQL that will be executed after the model has been created. Geometry
columns must be added after creation with the PostGIS AddGeometryColumn() function.""" 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) 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: if self._index:
# Creating geometry indices doesn't yet work. return '%s\n%s' % (post_sql, _geom_index(self._geom, *args, **kwargs))
#return '%s\n%s' % (post_sql, _geom_index(self._geom, *args, **kwargs))
return post_sql
else: else:
return post_sql return post_sql
@ -69,12 +94,16 @@ class GeometryField(Field):
def get_db_prep_save(self, value): def get_db_prep_save(self, value):
"Making sure the SRID is included before saving." "Making sure the SRID is included before saving."
return 'SRID=%d;%s' % (self._srid, value) return 'SRID=%d;%s' % (self._srid, value)
def get_manipulator_field_objs(self):
"Using the WKTField (defined above) to be our manipulator."
return [WKTField]
# The OpenGIS Geometry Type Fields # The OpenGIS Geometry Type Fields
class PointField(GeometryField): class PointField(GeometryField):
_geom = 'POINT' _geom = 'POINT'
class LineString(GeometryField): class LineStringField(GeometryField):
_geom = 'LINESTRING' _geom = 'LINESTRING'
class PolygonField(GeometryField): class PolygonField(GeometryField):

View File

@ -2,33 +2,31 @@
# django.db.models.query objects to be customized for PostGIS. # django.db.models.query objects to be customized for PostGIS.
from copy import copy from copy import copy
from django.db import backend from django.db import backend
from django.db.models.query import \ from django.db.models.query import LOOKUP_SEPARATOR, find_field, FieldFound
LOOKUP_SEPARATOR, QUERY_TERMS, \
find_field, FieldFound, get_where_clause
from django.utils.datastructures import SortedDict from django.utils.datastructures import SortedDict
# PostGIS-specific operators. The commented descriptions of these # PostGIS-specific operators. The commented descriptions of these
# operators come from Section 6.2.2 of the official PostGIS documentation. # operators come from Section 6.2.2 of the official PostGIS documentation.
POSTGIS_OPERATORS = { POSTGIS_OPERATORS = {
# The "&<" operator returns true if A's bounding box overlaps or is to the left of B's bounding box. # The "&<" operator returns true if A's bounding box overlaps or is to the left of B's bounding box.
'overlapsleft' : '&< %s', 'overlaps_left' : '&< %s',
# The "&>" operator returns true if A's bounding box overlaps or is to the right of B's bounding box. # The "&>" operator returns true if A's bounding box overlaps or is to the right of B's bounding box.
'overlapsright' : '&> %s', 'overlaps_right' : '&> %s',
# The "<<" operator returns true if A's bounding box is strictly to the left of B's bounding box. # The "<<" operator returns true if A's bounding box is strictly to the left of B's bounding box.
'left' : '<< %s', 'left' : '<< %s',
# The ">>" operator returns true if A's bounding box is strictly to the right of B's bounding box. # The ">>" operator returns true if A's bounding box is strictly to the right of B's bounding box.
'right' : '>> %s', 'right' : '>> %s',
# The "&<|" operator returns true if A's bounding box overlaps or is below B's bounding box. # The "&<|" operator returns true if A's bounding box overlaps or is below B's bounding box.
'overlapsbelow' : '&<| %s', 'overlaps_below' : '&<| %s',
# The "|&>" operator returns true if A's bounding box overlaps or is above B's bounding box. # The "|&>" operator returns true if A's bounding box overlaps or is above B's bounding box.
'overlapsabove' : '|&> %s', 'overlaps_above' : '|&> %s',
# The "<<|" operator returns true if A's bounding box is strictly below B's bounding box. # The "<<|" operator returns true if A's bounding box is strictly below B's bounding box.
'strictlybelow' : '<<| %s', 'strictly_below' : '<<| %s',
# The "|>>" operator returns true if A's bounding box is strictly above B's bounding box. # The "|>>" operator returns true if A's bounding box is strictly above B's bounding box.
'strictlyabove' : '|>> %s', 'strictly_above' : '|>> %s',
# 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.
'sameas' : '~= %s', 'same_as' : '~= %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.