tests.py 4.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. """
  2. Tests for geography support in PostGIS 1.5+
  3. """
  4. from __future__ import unicode_literals
  5. import os
  6. from unittest import skipUnless
  7. from django.contrib.gis.gdal import HAS_GDAL
  8. from django.contrib.gis.geos import HAS_GEOS
  9. from django.contrib.gis.measure import D
  10. from django.contrib.gis.tests.utils import postgis
  11. from django.test import TestCase
  12. from django.utils._os import upath
  13. if HAS_GEOS:
  14. from .models import City, County, Zipcode
  15. @skipUnless(HAS_GEOS and postgis, "Geos and postgis are required.")
  16. class GeographyTest(TestCase):
  17. def test01_fixture_load(self):
  18. "Ensure geography features loaded properly."
  19. self.assertEqual(8, City.objects.count())
  20. def test02_distance_lookup(self):
  21. "Testing GeoQuerySet distance lookup support on non-point geography fields."
  22. z = Zipcode.objects.get(code='77002')
  23. cities1 = list(City.objects
  24. .filter(point__distance_lte=(z.poly, D(mi=500)))
  25. .order_by('name')
  26. .values_list('name', flat=True))
  27. cities2 = list(City.objects
  28. .filter(point__dwithin=(z.poly, D(mi=500)))
  29. .order_by('name')
  30. .values_list('name', flat=True))
  31. for cities in [cities1, cities2]:
  32. self.assertEqual(['Dallas', 'Houston', 'Oklahoma City'], cities)
  33. def test03_distance_method(self):
  34. "Testing GeoQuerySet.distance() support on non-point geography fields."
  35. # `GeoQuerySet.distance` is not allowed geometry fields.
  36. htown = City.objects.get(name='Houston')
  37. Zipcode.objects.distance(htown.point)
  38. def test04_invalid_operators_functions(self):
  39. "Ensuring exceptions are raised for operators & functions invalid on geography fields."
  40. # Only a subset of the geometry functions & operator are available
  41. # to PostGIS geography types. For more information, visit:
  42. # http://postgis.refractions.net/documentation/manual-1.5/ch08.html#PostGIS_GeographyFunctions
  43. z = Zipcode.objects.get(code='77002')
  44. # ST_Within not available.
  45. self.assertRaises(ValueError, City.objects.filter(point__within=z.poly).count)
  46. # `@` operator not available.
  47. self.assertRaises(ValueError, City.objects.filter(point__contained=z.poly).count)
  48. # Regression test for #14060, `~=` was never really implemented for PostGIS.
  49. htown = City.objects.get(name='Houston')
  50. self.assertRaises(ValueError, City.objects.get, point__exact=htown.point)
  51. @skipUnless(HAS_GDAL, "GDAL is required.")
  52. def test05_geography_layermapping(self):
  53. "Testing LayerMapping support on models with geography fields."
  54. # There is a similar test in `layermap` that uses the same data set,
  55. # but the County model here is a bit different.
  56. from django.contrib.gis.utils import LayerMapping
  57. # Getting the shapefile and mapping dictionary.
  58. shp_path = os.path.realpath(os.path.join(os.path.dirname(upath(__file__)), '..', 'data'))
  59. co_shp = os.path.join(shp_path, 'counties', 'counties.shp')
  60. co_mapping = {'name': 'Name',
  61. 'state': 'State',
  62. 'mpoly': 'MULTIPOLYGON',
  63. }
  64. # Reference county names, number of polygons, and state names.
  65. names = ['Bexar', 'Galveston', 'Harris', 'Honolulu', 'Pueblo']
  66. num_polys = [1, 2, 1, 19, 1] # Number of polygons for each.
  67. st_names = ['Texas', 'Texas', 'Texas', 'Hawaii', 'Colorado']
  68. lm = LayerMapping(County, co_shp, co_mapping, source_srs=4269, unique='name')
  69. lm.save(silent=True, strict=True)
  70. for c, name, num_poly, state in zip(County.objects.order_by('name'), names, num_polys, st_names):
  71. self.assertEqual(4326, c.mpoly.srid)
  72. self.assertEqual(num_poly, len(c.mpoly))
  73. self.assertEqual(name, c.name)
  74. self.assertEqual(state, c.state)
  75. def test06_geography_area(self):
  76. "Testing that Area calculations work on geography columns."
  77. # SELECT ST_Area(poly) FROM geogapp_zipcode WHERE code='77002';
  78. ref_area = 5439084.70637573
  79. tol = 5
  80. z = Zipcode.objects.area().get(code='77002')
  81. self.assertAlmostEqual(z.area.sq_m, ref_area, tol)