| """ |
| 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, County, Zipcode |
| |
| class GeographyTest(TestCase): |
| |
| def test01_fixture_load(self): |
| "Ensure geography features loaded properly." |
| self.assertEqual(8, City.objects.count()) |
| |
| def test02_distance_lookup(self): |
| "Testing GeoQuerySet distance lookup support on non-point geography fields." |
| z = Zipcode.objects.get(code='77002') |
| 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 geography fields." |
| # `GeoQuerySet.distance` is not allowed geometry fields. |
| htown = City.objects.get(name='Houston') |
| qs = Zipcode.objects.distance(htown.point) |
| |
| def test04_invalid_operators_functions(self): |
| "Ensuring exceptions are raised for operators & functions invalid on geography fields." |
| # Only a subset of the geometry functions & operator are available |
| # to PostGIS geography types. For more information, visit: |
| # http://postgis.refractions.net/documentation/manual-1.5/ch08.html#PostGIS_GeographyFunctions |
| z = Zipcode.objects.get(code='77002') |
| # ST_Within not available. |
| 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) |
| |
| # Regression test for #14060, `~=` was never really implemented for PostGIS. |
| htown = City.objects.get(name='Houston') |
| self.assertRaises(ValueError, City.objects.get, point__exact=htown.point) |
| |
| 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) |
| |
| def test06_geography_area(self): |
| "Testing that Area calculations work on geography columns." |
| from django.contrib.gis.measure import A |
| # SELECT ST_Area(poly) FROM geogapp_zipcode WHERE code='77002'; |
| ref_area = 5439084.70637573 |
| tol = 5 |
| z = Zipcode.objects.area().get(code='77002') |
| self.assertAlmostEqual(z.area.sq_m, ref_area, tol) |