tests.py 4.6 KB

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