1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

gis: Added beginnings of django.contrib.gis.

Changed ManyToManyField to provide get_internal_type() -> 'NoField'.
GIS fields use NoField? and new _post_create_sql for AddGeometryColumn.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@4674 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jeremy Dunck 2007-03-07 23:09:33 +00:00
parent 5514d87319
commit 5edcbdc826
11 changed files with 155 additions and 5 deletions

View File

@ -0,0 +1,71 @@
from geos import geomFromWKT, geomToWKT
from decimal import Decimal
from django.db import models
from django.db.models.query import QuerySet
class GeoQuerySet(QuerySet):
# The list of valid query terms
# override the local QUERY_TERMS in the namespace
# not sure how to do that locals() hackery
# possibly in the init change its locals() variables
# not sure if that will work
QUERY_TERMS = (
'exact', 'iexact', 'contains', 'icontains', 'overlaps',
'gt', 'gte', 'lt', 'lte', 'in',
'startswith', 'istartswith', 'endswith', 'iendswith',
'range', 'year', 'month', 'day', 'isnull', 'search',
)
def dprint(arg):
import re
import inspect
print re.match("^\s*dprint\(\s*(.+)\s*\)", inspect.stack()[1][4][0]).group(1) + ": " + repr(arg)
class GeometryManager(models.Manager):
#def filter(self, *args, **kwargs):
# super(Manager, self).filter(*args, **kwargs)
# return self.get_query_set().filter(*args, **kwargs)
def get_query_set(self):
return GeoQuerySet(self.model)
class BoundingBox:
def _geom(self):
return geomToWKT(self._g)
geom = property(_geom)
def _area(self):
return self._g.area()
area = property(_area)
def __init__(self, ne, sw):
"""
Create a bounding box using two points
This points come from a JSON request, so they are strings
"""
ne = [Decimal(i.strip(' ')) for i in ne[1:-1].split(',')]
sw = [Decimal(i.strip(' ')) for i in sw[1:-1].split(',')]
ne_lat = ne[0]
ne_lng = ne[1]
sw_lat = sw[0]
sw_lng = sw[1]
bb = 'POLYGON(('
bb += str(ne_lng) + " " + str(ne_lat) + ","
bb += str(ne_lng) + " " + str(sw_lat) + ","
bb += str(sw_lng) + " " + str(sw_lat) + ","
bb += str(sw_lng) + " " + str(ne_lat) + ","
bb += str(ne_lng) + " " + str(ne_lat)
bb += '))'
self._g = geomFromWKT(bb)

View File

View File

View File

@ -0,0 +1,72 @@
from django.db import models
from django.db.models.fields import Field
#from GeoTypes import Point
# Creates the SQL to add the model to the database. Defaults to using an
# SRID of 4326 (WGS84 Datum -- 'normal' lat/lon coordinates)
def _add_geom(geom, srid, style, model, field, dim=2):
from django.db import backend
# 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_KEYWORD(geom) + "', " + \
style.SQL_KEYWORD(str(dim)) + \
');'
return sql
class GeometryField(Field):
"""The base GIS field -- maps to an OpenGIS Geometry type."""
_geom = 'GEOMETRY'
_srid = 4326
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."""
return _add_geom(self._geom, self._srid, *args, **kwargs)
def get_db_prep_lookup(self, lookup_type, value):
"Returns field's value prepared for database lookup."
if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'month', 'day', 'search', 'overlaps'):
return [value]
elif lookup_type in ('range', 'in'):
return value
elif lookup_type in ('contains', 'icontains'):
return ["%%%s%%" % prep_for_like_query(value)]
elif lookup_type == 'iexact':
return [prep_for_like_query(value)]
elif lookup_type in ('startswith', 'istartswith'):
return ["%s%%" % prep_for_like_query(value)]
elif lookup_type in ('endswith', 'iendswith'):
return ["%%%s" % prep_for_like_query(value)]
elif lookup_type == 'isnull':
return []
elif lookup_type == 'year':
try:
value = int(value)
except ValueError:
raise ValueError("The __year lookup type requires an integer argument")
return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.999999' % value]
raise TypeError("Field has invalid lookup: %s" % lookup_type)
def get_db_prep_save(self, value):
return 'SRID=%d;%s' % (self._srid, value)
class PointField(GeometryField):
_geom = 'POINT'
class PolygonField(GeometryField):
_geom = 'POLYGON'
class MultiPolygonField(GeometryField):
_geom = 'MULTIPOLYGON'
class GeometryManager(models.Manager):
pass

View File

@ -386,6 +386,10 @@ def get_custom_sql_for_model(model):
output.append(statement + ";")
fp.close()
for f in opts.fields:
if hasattr(f, '_post_create_sql'):
output.append(f._post_create_sql(style, model._meta.db_table, f.column))
return output
def get_custom_sql(app):

View File

@ -11,7 +11,6 @@ DATA_TYPES = {
'ImageField': 'varchar(100)',
'IntegerField': 'int',
'IPAddressField': 'char(15)',
'ManyToManyField': None,
'NullBooleanField': 'bit',
'OneToOneField': 'int',
'PhoneNumberField': 'varchar(20)',
@ -22,4 +21,5 @@ DATA_TYPES = {
'TextField': 'text',
'TimeField': 'time',
'USStateField': 'varchar(2)',
'NoField': None,
}

View File

@ -15,7 +15,6 @@ DATA_TYPES = {
'ImageField': 'varchar(100)',
'IntegerField': 'integer',
'IPAddressField': 'char(15)',
'ManyToManyField': None,
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PhoneNumberField': 'varchar(20)',
@ -26,4 +25,5 @@ DATA_TYPES = {
'TextField': 'longtext',
'TimeField': 'time',
'USStateField': 'varchar(2)',
'NoField': None,
}

View File

@ -11,7 +11,6 @@ DATA_TYPES = {
'ImageField': 'varchar2(100)',
'IntegerField': 'integer',
'IPAddressField': 'char(15)',
'ManyToManyField': None,
'NullBooleanField': 'integer',
'OneToOneField': 'integer',
'PhoneNumberField': 'varchar(20)',
@ -22,4 +21,5 @@ DATA_TYPES = {
'TextField': 'long',
'TimeField': 'timestamp',
'USStateField': 'varchar(2)',
'NoField': None,
}

View File

@ -15,7 +15,6 @@ DATA_TYPES = {
'ImageField': 'varchar(100)',
'IntegerField': 'integer',
'IPAddressField': 'inet',
'ManyToManyField': None,
'NullBooleanField': 'boolean',
'OneToOneField': 'integer',
'PhoneNumberField': 'varchar(20)',
@ -26,4 +25,5 @@ DATA_TYPES = {
'TextField': 'text',
'TimeField': 'time',
'USStateField': 'varchar(2)',
'NoField': None,
}

View File

@ -14,7 +14,6 @@ DATA_TYPES = {
'ImageField': 'varchar(100)',
'IntegerField': 'integer',
'IPAddressField': 'char(15)',
'ManyToManyField': None,
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PhoneNumberField': 'varchar(20)',
@ -25,4 +24,5 @@ DATA_TYPES = {
'TextField': 'text',
'TimeField': 'time',
'USStateField': 'varchar(2)',
'NoField': None,
}

View File

@ -644,6 +644,9 @@ class ManyToManyField(RelatedField, Field):
msg = gettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.')
self.help_text = string_concat(self.help_text, ' ', msg)
def get_internal_type(self):
return "NoField"
def get_manipulator_field_objs(self):
if self.rel.raw_id_admin:
return [oldforms.RawIdAdminField]