Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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
  • Loading branch information...
commit ac6273d6750be112dcb909d2201104be5885e806 1 parent 7626f85
@jbronn jbronn authored
View
7 django/contrib/gis/tests/geogapp/models.py
@@ -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])
View
59 django/contrib/gis/tests/geogapp/tests.py
@@ -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 @@ def test01_fixture_load(self):
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 @@ def test04_invalid_operators_functions(self):
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)
View
1  django/contrib/gis/tests/geogapp/views.py
@@ -1 +0,0 @@
-# Create your views here.
View
33 django/contrib/gis/utils/layermapping.py
@@ -97,7 +97,7 @@ def __init__(self, model, data, mapping, layer=0,
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 @@ def coord_transform(self):
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):
"""
Please sign in to comment.
Something went wrong with that request. Please try again.