Fixed `LayerMapping` to work with PostGIS geography fields; removed `LayerMapping.geometry_column` and replaced with `LayerMapping.geometry_field` because getting the `geometry_columns` entry was completely unnecessary, and only the geometry field instance is needed; cleaned up and fleshed out the `geogapp` tests.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@11983 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
7626f851e3
commit
ac6273d675
|
@ -11,3 +11,10 @@ class Zipcode(models.Model):
|
|||
poly = models.PolygonField(geography=True)
|
||||
objects = models.GeoManager()
|
||||
def __unicode__(self): return self.name
|
||||
|
||||
class County(models.Model):
|
||||
name = models.CharField(max_length=25)
|
||||
state = models.CharField(max_length=20)
|
||||
mpoly = models.MultiPolygonField(geography=True)
|
||||
objects = models.GeoManager()
|
||||
def __unicode__(self): return ' County, '.join([self.name, self.state])
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
"""
|
||||
This file demonstrates two different styles of tests (one doctest and one
|
||||
unittest). These will both pass when you run "manage.py test".
|
||||
|
||||
Replace these with more appropriate tests for your application.
|
||||
Tests for geography support in PostGIS 1.5+
|
||||
"""
|
||||
import os
|
||||
from django.contrib.gis import gdal
|
||||
from django.contrib.gis.measure import D
|
||||
from django.test import TestCase
|
||||
from models import City, Zipcode
|
||||
from models import City, County, Zipcode
|
||||
|
||||
class GeographyTest(TestCase):
|
||||
|
||||
|
@ -15,17 +14,22 @@ class GeographyTest(TestCase):
|
|||
self.assertEqual(8, City.objects.count())
|
||||
|
||||
def test02_distance_lookup(self):
|
||||
"Testing GeoQuerySet distance lookup support on non-point geometry fields."
|
||||
"Testing GeoQuerySet distance lookup support on non-point geography fields."
|
||||
z = Zipcode.objects.get(code='77002')
|
||||
cities = list(City.objects
|
||||
.filter(point__distance_lte=(z.poly, D(mi=500)))
|
||||
.order_by('name')
|
||||
.values_list('name', flat=True))
|
||||
self.assertEqual(['Dallas', 'Houston', 'Oklahoma City'], cities)
|
||||
cities1 = list(City.objects
|
||||
.filter(point__distance_lte=(z.poly, D(mi=500)))
|
||||
.order_by('name')
|
||||
.values_list('name', flat=True))
|
||||
cities2 = list(City.objects
|
||||
.filter(point__dwithin=(z.poly, D(mi=500)))
|
||||
.order_by('name')
|
||||
.values_list('name', flat=True))
|
||||
for cities in [cities1, cities2]:
|
||||
self.assertEqual(['Dallas', 'Houston', 'Oklahoma City'], cities)
|
||||
|
||||
def test03_distance_method(self):
|
||||
"Testing GeoQuerySet.distance() support on non-point geometry fields."
|
||||
# Can't do this with geometry fields:
|
||||
"Testing GeoQuerySet.distance() support on non-point geography fields."
|
||||
# `GeoQuerySet.distance` is not allowed geometry fields.
|
||||
htown = City.objects.get(name='Houston')
|
||||
qs = Zipcode.objects.distance(htown.point)
|
||||
|
||||
|
@ -39,3 +43,32 @@ class GeographyTest(TestCase):
|
|||
self.assertRaises(ValueError, City.objects.filter(point__within=z.poly).count)
|
||||
# `@` operator not available.
|
||||
self.assertRaises(ValueError, City.objects.filter(point__contained=z.poly).count)
|
||||
|
||||
def test05_geography_layermapping(self):
|
||||
"Testing LayerMapping support on models with geography fields."
|
||||
# There is a similar test in `layermap` that uses the same data set,
|
||||
# but the County model here is a bit different.
|
||||
if not gdal.HAS_GDAL: return
|
||||
from django.contrib.gis.utils import LayerMapping
|
||||
|
||||
# Getting the shapefile and mapping dictionary.
|
||||
shp_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'data'))
|
||||
co_shp = os.path.join(shp_path, 'counties', 'counties.shp')
|
||||
co_mapping = {'name' : 'Name',
|
||||
'state' : 'State',
|
||||
'mpoly' : 'MULTIPOLYGON',
|
||||
}
|
||||
|
||||
# Reference county names, number of polygons, and state names.
|
||||
names = ['Bexar', 'Galveston', 'Harris', 'Honolulu', 'Pueblo']
|
||||
num_polys = [1, 2, 1, 19, 1] # Number of polygons for each.
|
||||
st_names = ['Texas', 'Texas', 'Texas', 'Hawaii', 'Colorado']
|
||||
|
||||
lm = LayerMapping(County, co_shp, co_mapping, source_srs=4269, unique='name')
|
||||
lm.save(silent=True, strict=True)
|
||||
|
||||
for c, name, num_poly, state in zip(County.objects.order_by('name'), names, num_polys, st_names):
|
||||
self.assertEqual(4326, c.mpoly.srid)
|
||||
self.assertEqual(num_poly, len(c.mpoly))
|
||||
self.assertEqual(name, c.name)
|
||||
self.assertEqual(state, c.state)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
# Create your views here.
|
|
@ -97,7 +97,7 @@ class LayerMapping(object):
|
|||
if self.spatial_backend.mysql:
|
||||
transform = False
|
||||
else:
|
||||
self.geo_col = self.geometry_column()
|
||||
self.geo_field = self.geometry_field()
|
||||
|
||||
# Checking the source spatial reference system, and getting
|
||||
# the coordinate transformation object (unless the `transform`
|
||||
|
@ -426,41 +426,20 @@ class LayerMapping(object):
|
|||
SpatialRefSys = self.spatial_backend.spatial_ref_sys()
|
||||
try:
|
||||
# Getting the target spatial reference system
|
||||
target_srs = SpatialRefSys.objects.get(srid=self.geo_col.srid).srs
|
||||
target_srs = SpatialRefSys.objects.get(srid=self.geo_field.srid).srs
|
||||
|
||||
# Creating the CoordTransform object
|
||||
return CoordTransform(self.source_srs, target_srs)
|
||||
except Exception, msg:
|
||||
raise LayerMapError('Could not translate between the data source and model geometry: %s' % msg)
|
||||
|
||||
def geometry_column(self):
|
||||
"Returns the GeometryColumn model associated with the geographic column."
|
||||
def geometry_field(self):
|
||||
"Returns the GeometryField instance associated with the geographic column."
|
||||
# Use the `get_field_by_name` on the model's options so that we
|
||||
# get the correct model if there's model inheritance -- otherwise
|
||||
# the returned model is None.
|
||||
# get the correct field instance if there's model inheritance.
|
||||
opts = self.model._meta
|
||||
fld, model, direct, m2m = opts.get_field_by_name(self.geom_field)
|
||||
if model is None: model = self.model
|
||||
|
||||
# Trying to get the `GeometryColumns` object that corresponds to the
|
||||
# the geometry field.
|
||||
try:
|
||||
db_table = model._meta.db_table
|
||||
geo_col = fld.column
|
||||
|
||||
if self.spatial_backend.oracle:
|
||||
# Making upper case for Oracle.
|
||||
db_table = db_table.upper()
|
||||
geo_col = geo_col.upper()
|
||||
|
||||
GeometryColumns = self.spatial_backend.geometry_columns()
|
||||
|
||||
gc_kwargs = { GeometryColumns.table_name_col() : db_table,
|
||||
GeometryColumns.geom_col_name() : geo_col,
|
||||
}
|
||||
return GeometryColumns.objects.get(**gc_kwargs)
|
||||
except Exception, msg:
|
||||
raise LayerMapError('Geometry column does not exist for model. (did you run syncdb?):\n %s' % msg)
|
||||
return fld
|
||||
|
||||
def make_multi(self, geom_type, model_field):
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue