Removed redundant database vendor helpers in gis_tests/utils.py.
This commit is contained in:
parent
9f91122ed8
commit
e3ece0144a
|
@ -12,6 +12,7 @@ class BaseSpatialOperations:
|
||||||
# an attribute for the spatial database version tuple (if applicable)
|
# an attribute for the spatial database version tuple (if applicable)
|
||||||
postgis = False
|
postgis = False
|
||||||
spatialite = False
|
spatialite = False
|
||||||
|
mariadb = False
|
||||||
mysql = False
|
mysql = False
|
||||||
oracle = False
|
oracle = False
|
||||||
spatial_version = None
|
spatial_version = None
|
||||||
|
|
|
@ -12,13 +12,19 @@ from django.utils.functional import cached_property
|
||||||
|
|
||||||
|
|
||||||
class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
|
class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
|
||||||
|
|
||||||
mysql = True
|
|
||||||
name = 'mysql'
|
name = 'mysql'
|
||||||
geom_func_prefix = 'ST_'
|
geom_func_prefix = 'ST_'
|
||||||
|
|
||||||
Adapter = WKTAdapter
|
Adapter = WKTAdapter
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def mariadb(self):
|
||||||
|
return self.connection.mysql_is_mariadb
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def mysql(self):
|
||||||
|
return not self.connection.mysql_is_mariadb
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def select(self):
|
def select(self):
|
||||||
return self.geom_func_prefix + 'AsBinary(%s)'
|
return self.geom_func_prefix + 'AsBinary(%s)'
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import unittest
|
|
||||||
|
|
||||||
from django.contrib.gis.db.models.functions import (
|
from django.contrib.gis.db.models.functions import (
|
||||||
Area, Distance, Length, Perimeter, Transform, Union,
|
Area, Distance, Length, Perimeter, Transform, Union,
|
||||||
)
|
)
|
||||||
|
@ -9,7 +7,7 @@ from django.db import NotSupportedError, connection
|
||||||
from django.db.models import Exists, F, OuterRef, Q
|
from django.db.models import Exists, F, OuterRef, Q
|
||||||
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
|
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
|
||||||
|
|
||||||
from ..utils import FuncTestMixin, mysql, oracle, postgis, spatialite
|
from ..utils import FuncTestMixin
|
||||||
from .models import (
|
from .models import (
|
||||||
AustraliaCity, CensusZipcode, Interstate, SouthTexasCity, SouthTexasCityFt,
|
AustraliaCity, CensusZipcode, Interstate, SouthTexasCity, SouthTexasCityFt,
|
||||||
SouthTexasInterstate, SouthTexasZipcode,
|
SouthTexasInterstate, SouthTexasZipcode,
|
||||||
|
@ -79,9 +77,9 @@ class DistanceTest(TestCase):
|
||||||
# Now performing the `dwithin` queries on a geodetic coordinate system.
|
# Now performing the `dwithin` queries on a geodetic coordinate system.
|
||||||
for dist in au_dists:
|
for dist in au_dists:
|
||||||
with self.subTest(dist=dist):
|
with self.subTest(dist=dist):
|
||||||
type_error = isinstance(dist, D) and not oracle
|
type_error = isinstance(dist, D) and not connection.ops.oracle
|
||||||
if isinstance(dist, tuple):
|
if isinstance(dist, tuple):
|
||||||
if oracle or spatialite:
|
if connection.ops.oracle or connection.ops.spatialite:
|
||||||
# Result in meters
|
# Result in meters
|
||||||
dist = dist[1]
|
dist = dist[1]
|
||||||
else:
|
else:
|
||||||
|
@ -137,7 +135,7 @@ class DistanceTest(TestCase):
|
||||||
'Melbourne', 'Mittagong', 'Shellharbour',
|
'Melbourne', 'Mittagong', 'Shellharbour',
|
||||||
'Sydney', 'Thirroul', 'Wollongong',
|
'Sydney', 'Thirroul', 'Wollongong',
|
||||||
]
|
]
|
||||||
if spatialite:
|
if connection.ops.spatialite:
|
||||||
# SpatiaLite is less accurate and returns 102.8km for Batemans Bay.
|
# SpatiaLite is less accurate and returns 102.8km for Batemans Bay.
|
||||||
expected_cities.pop(0)
|
expected_cities.pop(0)
|
||||||
self.assertEqual(expected_cities, self.get_names(dist_qs))
|
self.assertEqual(expected_cities, self.get_names(dist_qs))
|
||||||
|
@ -216,8 +214,9 @@ class DistanceTest(TestCase):
|
||||||
SouthTexasCity.objects.count(),
|
SouthTexasCity.objects.count(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@unittest.skipUnless(mysql, 'This is a MySQL-specific test')
|
|
||||||
def test_mysql_geodetic_distance_error(self):
|
def test_mysql_geodetic_distance_error(self):
|
||||||
|
if not connection.ops.mysql:
|
||||||
|
self.skipTest('This is a MySQL-specific test.')
|
||||||
msg = 'Only numeric values of degree units are allowed on geodetic distance queries.'
|
msg = 'Only numeric values of degree units are allowed on geodetic distance queries.'
|
||||||
with self.assertRaisesMessage(ValueError, msg):
|
with self.assertRaisesMessage(ValueError, msg):
|
||||||
AustraliaCity.objects.filter(point__distance_lte=(Point(0, 0), D(m=100))).exists()
|
AustraliaCity.objects.filter(point__distance_lte=(Point(0, 0), D(m=100))).exists()
|
||||||
|
@ -313,7 +312,7 @@ class DistanceFunctionsTests(FuncTestMixin, TestCase):
|
||||||
"""
|
"""
|
||||||
lagrange = GEOSGeometry('POINT(805066.295722839 4231496.29461335)', 32140)
|
lagrange = GEOSGeometry('POINT(805066.295722839 4231496.29461335)', 32140)
|
||||||
houston = SouthTexasCity.objects.annotate(dist=Distance('point', lagrange)).order_by('id').first()
|
houston = SouthTexasCity.objects.annotate(dist=Distance('point', lagrange)).order_by('id').first()
|
||||||
tol = 2 if oracle else 5
|
tol = 2 if connection.ops.oracle else 5
|
||||||
self.assertAlmostEqual(
|
self.assertAlmostEqual(
|
||||||
houston.dist.m,
|
houston.dist.m,
|
||||||
147075.069813,
|
147075.069813,
|
||||||
|
@ -348,7 +347,7 @@ class DistanceFunctionsTests(FuncTestMixin, TestCase):
|
||||||
|
|
||||||
# Original query done on PostGIS, have to adjust AlmostEqual tolerance
|
# Original query done on PostGIS, have to adjust AlmostEqual tolerance
|
||||||
# for Oracle.
|
# for Oracle.
|
||||||
tol = 2 if oracle else 5
|
tol = 2 if connection.ops.oracle else 5
|
||||||
|
|
||||||
# Ensuring expected distances are returned for each distance queryset.
|
# Ensuring expected distances are returned for each distance queryset.
|
||||||
for qs in dist_qs:
|
for qs in dist_qs:
|
||||||
|
@ -376,12 +375,12 @@ class DistanceFunctionsTests(FuncTestMixin, TestCase):
|
||||||
for city, distance in zip(qs, distances):
|
for city, distance in zip(qs, distances):
|
||||||
with self.subTest(city=city, distance=distance):
|
with self.subTest(city=city, distance=distance):
|
||||||
# Testing equivalence to within a meter (kilometer on SpatiaLite).
|
# Testing equivalence to within a meter (kilometer on SpatiaLite).
|
||||||
tol = -3 if spatialite else 0
|
tol = -3 if connection.ops.spatialite else 0
|
||||||
self.assertAlmostEqual(distance, city.distance.m, tol)
|
self.assertAlmostEqual(distance, city.distance.m, tol)
|
||||||
|
|
||||||
@skipUnlessDBFeature("has_Distance_function", "supports_distance_geodetic")
|
@skipUnlessDBFeature("has_Distance_function", "supports_distance_geodetic")
|
||||||
def test_distance_geodetic_spheroid(self):
|
def test_distance_geodetic_spheroid(self):
|
||||||
tol = 2 if oracle else 4
|
tol = 2 if connection.ops.oracle else 4
|
||||||
|
|
||||||
# Got the reference distances using the raw SQL statements:
|
# Got the reference distances using the raw SQL statements:
|
||||||
# SELECT ST_distance_spheroid(point, ST_GeomFromText('POINT(151.231341 -33.952685)', 4326),
|
# SELECT ST_distance_spheroid(point, ST_GeomFromText('POINT(151.231341 -33.952685)', 4326),
|
||||||
|
@ -408,7 +407,7 @@ class DistanceFunctionsTests(FuncTestMixin, TestCase):
|
||||||
for i, c in enumerate(qs):
|
for i, c in enumerate(qs):
|
||||||
with self.subTest(c=c):
|
with self.subTest(c=c):
|
||||||
self.assertAlmostEqual(spheroid_distances[i], c.distance.m, tol)
|
self.assertAlmostEqual(spheroid_distances[i], c.distance.m, tol)
|
||||||
if postgis or spatialite:
|
if connection.ops.postgis or connection.ops.spatialite:
|
||||||
# PostGIS uses sphere-only distances by default, testing these as well.
|
# PostGIS uses sphere-only distances by default, testing these as well.
|
||||||
qs = AustraliaCity.objects.exclude(id=hillsdale.id).annotate(
|
qs = AustraliaCity.objects.exclude(id=hillsdale.id).annotate(
|
||||||
distance=Distance('point', hillsdale.point)
|
distance=Distance('point', hillsdale.point)
|
||||||
|
@ -521,7 +520,7 @@ class DistanceFunctionsTests(FuncTestMixin, TestCase):
|
||||||
|
|
||||||
if connection.features.supports_length_geodetic:
|
if connection.features.supports_length_geodetic:
|
||||||
qs = Interstate.objects.annotate(length=Length('path'))
|
qs = Interstate.objects.annotate(length=Length('path'))
|
||||||
tol = 2 if oracle else 3
|
tol = 2 if connection.ops.oracle else 3
|
||||||
self.assertAlmostEqual(len_m1, qs[0].length.m, tol)
|
self.assertAlmostEqual(len_m1, qs[0].length.m, tol)
|
||||||
# TODO: test with spheroid argument (True and False)
|
# TODO: test with spheroid argument (True and False)
|
||||||
else:
|
else:
|
||||||
|
@ -547,7 +546,7 @@ class DistanceFunctionsTests(FuncTestMixin, TestCase):
|
||||||
# Reference query:
|
# Reference query:
|
||||||
# SELECT ST_Perimeter(distapp_southtexaszipcode.poly) FROM distapp_southtexaszipcode;
|
# SELECT ST_Perimeter(distapp_southtexaszipcode.poly) FROM distapp_southtexaszipcode;
|
||||||
perim_m = [18404.3550889361, 15627.2108551001, 20632.5588368978, 17094.5996143697]
|
perim_m = [18404.3550889361, 15627.2108551001, 20632.5588368978, 17094.5996143697]
|
||||||
tol = 2 if oracle else 7
|
tol = 2 if connection.ops.oracle else 7
|
||||||
qs = SouthTexasZipcode.objects.annotate(perimeter=Perimeter('poly')).order_by('name')
|
qs = SouthTexasZipcode.objects.annotate(perimeter=Perimeter('poly')).order_by('name')
|
||||||
for i, z in enumerate(qs):
|
for i, z in enumerate(qs):
|
||||||
self.assertAlmostEqual(perim_m[i], z.perimeter.m, tol)
|
self.assertAlmostEqual(perim_m[i], z.perimeter.m, tol)
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
from unittest import skipUnless
|
|
||||||
|
|
||||||
from django.contrib.gis.db.models import F, GeometryField, Value, functions
|
from django.contrib.gis.db.models import F, GeometryField, Value, functions
|
||||||
from django.contrib.gis.geos import Point, Polygon
|
from django.contrib.gis.geos import Point, Polygon
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.db.models import Count, Min
|
from django.db.models import Count, Min
|
||||||
from django.test import TestCase, skipUnlessDBFeature
|
from django.test import TestCase, skipUnlessDBFeature
|
||||||
|
|
||||||
from ..utils import postgis
|
|
||||||
from .models import City, ManyPointModel, MultiFields
|
from .models import City, ManyPointModel, MultiFields
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,7 +22,7 @@ class GeoExpressionsTests(TestCase):
|
||||||
self.assertTrue(point.equals_exact(p.transform(4326, clone=True), 10 ** -5))
|
self.assertTrue(point.equals_exact(p.transform(4326, clone=True), 10 ** -5))
|
||||||
self.assertEqual(point.srid, 4326)
|
self.assertEqual(point.srid, 4326)
|
||||||
|
|
||||||
@skipUnless(postgis, 'Only postgis has geography fields.')
|
@skipUnlessDBFeature('supports_geography')
|
||||||
def test_geography_value(self):
|
def test_geography_value(self):
|
||||||
p = Polygon(((1, 1), (1, 2), (2, 2), (2, 1), (1, 1)))
|
p = Polygon(((1, 1), (1, 2), (2, 2), (2, 1), (1, 1)))
|
||||||
area = City.objects.annotate(a=functions.Area(Value(p, GeometryField(srid=4326, geography=True)))).first().a
|
area = City.objects.annotate(a=functions.Area(Value(p, GeometryField(srid=4326, geography=True)))).first().a
|
||||||
|
|
|
@ -12,7 +12,7 @@ from django.db import NotSupportedError, connection
|
||||||
from django.db.models import IntegerField, Sum, Value
|
from django.db.models import IntegerField, Sum, Value
|
||||||
from django.test import TestCase, skipUnlessDBFeature
|
from django.test import TestCase, skipUnlessDBFeature
|
||||||
|
|
||||||
from ..utils import FuncTestMixin, mariadb, mysql, oracle, postgis
|
from ..utils import FuncTestMixin
|
||||||
from .models import City, Country, CountryWebMercator, State, Track
|
from .models import City, Country, CountryWebMercator, State, Track
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
# WHERE "geoapp_city"."name" = 'Chicago';
|
# WHERE "geoapp_city"."name" = 'Chicago';
|
||||||
# Finally, we set every available keyword.
|
# Finally, we set every available keyword.
|
||||||
# MariaDB doesn't limit the number of decimals in bbox.
|
# MariaDB doesn't limit the number of decimals in bbox.
|
||||||
if mariadb:
|
if connection.ops.mariadb:
|
||||||
chicago_json['bbox'] = [-87.650175, 41.850385, -87.650175, 41.850385]
|
chicago_json['bbox'] = [-87.650175, 41.850385, -87.650175, 41.850385]
|
||||||
self.assertJSONEqual(
|
self.assertJSONEqual(
|
||||||
City.objects.annotate(
|
City.objects.annotate(
|
||||||
|
@ -105,7 +105,7 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
qs.annotate(gml=functions.AsGML('name'))
|
qs.annotate(gml=functions.AsGML('name'))
|
||||||
ptown = City.objects.annotate(gml=functions.AsGML('point', precision=9)).get(name='Pueblo')
|
ptown = City.objects.annotate(gml=functions.AsGML('point', precision=9)).get(name='Pueblo')
|
||||||
|
|
||||||
if oracle:
|
if connection.ops.oracle:
|
||||||
# No precision parameter for Oracle :-/
|
# No precision parameter for Oracle :-/
|
||||||
gml_regex = re.compile(
|
gml_regex = re.compile(
|
||||||
r'^<gml:Point srsName="EPSG:4326" xmlns:gml="http://www.opengis.net/gml">'
|
r'^<gml:Point srsName="EPSG:4326" xmlns:gml="http://www.opengis.net/gml">'
|
||||||
|
@ -167,7 +167,7 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
wkt = City.objects.annotate(
|
wkt = City.objects.annotate(
|
||||||
wkt=functions.AsWKT(Point(1, 2, srid=4326)),
|
wkt=functions.AsWKT(Point(1, 2, srid=4326)),
|
||||||
).first().wkt
|
).first().wkt
|
||||||
self.assertEqual(wkt, 'POINT (1.0 2.0)' if oracle else 'POINT(1 2)')
|
self.assertEqual(wkt, 'POINT (1.0 2.0)' if connection.ops.oracle else 'POINT(1 2)')
|
||||||
|
|
||||||
@skipUnlessDBFeature("has_Azimuth_function")
|
@skipUnlessDBFeature("has_Azimuth_function")
|
||||||
def test_azimuth(self):
|
def test_azimuth(self):
|
||||||
|
@ -184,11 +184,11 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
# num_seg is the number of segments per quarter circle.
|
# num_seg is the number of segments per quarter circle.
|
||||||
return (4 * num_seg) + 1
|
return (4 * num_seg) + 1
|
||||||
|
|
||||||
expected_areas = (169, 136) if postgis else (171, 126)
|
expected_areas = (169, 136) if connection.ops.postgis else (171, 126)
|
||||||
qs = Country.objects.annotate(circle=functions.BoundingCircle('mpoly')).order_by('name')
|
qs = Country.objects.annotate(circle=functions.BoundingCircle('mpoly')).order_by('name')
|
||||||
self.assertAlmostEqual(qs[0].circle.area, expected_areas[0], 0)
|
self.assertAlmostEqual(qs[0].circle.area, expected_areas[0], 0)
|
||||||
self.assertAlmostEqual(qs[1].circle.area, expected_areas[1], 0)
|
self.assertAlmostEqual(qs[1].circle.area, expected_areas[1], 0)
|
||||||
if postgis:
|
if connection.ops.postgis:
|
||||||
# By default num_seg=48.
|
# By default num_seg=48.
|
||||||
self.assertEqual(qs[0].circle.num_points, circle_num_points(48))
|
self.assertEqual(qs[0].circle.num_points, circle_num_points(48))
|
||||||
self.assertEqual(qs[1].circle.num_points, circle_num_points(48))
|
self.assertEqual(qs[1].circle.num_points, circle_num_points(48))
|
||||||
|
@ -199,7 +199,7 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
qs = Country.objects.annotate(
|
qs = Country.objects.annotate(
|
||||||
circle=functions.BoundingCircle('mpoly', num_seg=num_seq),
|
circle=functions.BoundingCircle('mpoly', num_seg=num_seq),
|
||||||
).order_by('name')
|
).order_by('name')
|
||||||
if postgis:
|
if connection.ops.postgis:
|
||||||
self.assertGreater(qs[0].circle.area, 168.4, 0)
|
self.assertGreater(qs[0].circle.area, 168.4, 0)
|
||||||
self.assertLess(qs[0].circle.area, 169.5, 0)
|
self.assertLess(qs[0].circle.area, 169.5, 0)
|
||||||
self.assertAlmostEqual(qs[1].circle.area, 136, 0)
|
self.assertAlmostEqual(qs[1].circle.area, 136, 0)
|
||||||
|
@ -212,7 +212,7 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
@skipUnlessDBFeature("has_Centroid_function")
|
@skipUnlessDBFeature("has_Centroid_function")
|
||||||
def test_centroid(self):
|
def test_centroid(self):
|
||||||
qs = State.objects.exclude(poly__isnull=True).annotate(centroid=functions.Centroid('poly'))
|
qs = State.objects.exclude(poly__isnull=True).annotate(centroid=functions.Centroid('poly'))
|
||||||
tol = 1.8 if mysql else (0.1 if oracle else 0.00001)
|
tol = 1.8 if connection.ops.mysql else (0.1 if connection.ops.oracle else 0.00001)
|
||||||
for state in qs:
|
for state in qs:
|
||||||
self.assertTrue(state.poly.centroid.equals_exact(state.centroid, tol))
|
self.assertTrue(state.poly.centroid.equals_exact(state.centroid, tol))
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
geom = Point(5, 23, srid=4326)
|
geom = Point(5, 23, srid=4326)
|
||||||
qs = Country.objects.annotate(diff=functions.Difference('mpoly', geom))
|
qs = Country.objects.annotate(diff=functions.Difference('mpoly', geom))
|
||||||
# Oracle does something screwy with the Texas geometry.
|
# Oracle does something screwy with the Texas geometry.
|
||||||
if oracle:
|
if connection.ops.oracle:
|
||||||
qs = qs.exclude(name='Texas')
|
qs = qs.exclude(name='Texas')
|
||||||
|
|
||||||
for c in qs:
|
for c in qs:
|
||||||
|
@ -236,7 +236,7 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
geom = Point(556597.4, 2632018.6, srid=3857) # Spherical Mercator
|
geom = Point(556597.4, 2632018.6, srid=3857) # Spherical Mercator
|
||||||
qs = Country.objects.annotate(difference=functions.Difference('mpoly', geom))
|
qs = Country.objects.annotate(difference=functions.Difference('mpoly', geom))
|
||||||
# Oracle does something screwy with the Texas geometry.
|
# Oracle does something screwy with the Texas geometry.
|
||||||
if oracle:
|
if connection.ops.oracle:
|
||||||
qs = qs.exclude(name='Texas')
|
qs = qs.exclude(name='Texas')
|
||||||
for c in qs:
|
for c in qs:
|
||||||
self.assertTrue(c.mpoly.difference(geom).equals(c.difference))
|
self.assertTrue(c.mpoly.difference(geom).equals(c.difference))
|
||||||
|
@ -396,9 +396,9 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
|
|
||||||
qs = City.objects.filter(point__isnull=False).annotate(num_geom=functions.NumGeometries('point'))
|
qs = City.objects.filter(point__isnull=False).annotate(num_geom=functions.NumGeometries('point'))
|
||||||
for city in qs:
|
for city in qs:
|
||||||
# Oracle and PostGIS return 1 for the number of geometries on
|
# The results for the number of geometries on non-collections
|
||||||
# non-collections, whereas MySQL returns None.
|
# depends on the database.
|
||||||
if mysql:
|
if connection.ops.mysql or connection.ops.mariadb:
|
||||||
self.assertIsNone(city.num_geom)
|
self.assertIsNone(city.num_geom)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(1, city.num_geom)
|
self.assertEqual(1, city.num_geom)
|
||||||
|
@ -519,7 +519,7 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
geom = Point(5, 23, srid=4326)
|
geom = Point(5, 23, srid=4326)
|
||||||
qs = Country.objects.annotate(sym_difference=functions.SymDifference('mpoly', geom))
|
qs = Country.objects.annotate(sym_difference=functions.SymDifference('mpoly', geom))
|
||||||
# Oracle does something screwy with the Texas geometry.
|
# Oracle does something screwy with the Texas geometry.
|
||||||
if oracle:
|
if connection.ops.oracle:
|
||||||
qs = qs.exclude(name='Texas')
|
qs = qs.exclude(name='Texas')
|
||||||
for country in qs:
|
for country in qs:
|
||||||
self.assertTrue(country.mpoly.sym_difference(geom).equals(country.sym_difference))
|
self.assertTrue(country.mpoly.sym_difference(geom).equals(country.sym_difference))
|
||||||
|
@ -562,7 +562,7 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
intersection=functions.Intersection('mpoly', geom),
|
intersection=functions.Intersection('mpoly', geom),
|
||||||
)
|
)
|
||||||
|
|
||||||
if oracle:
|
if connection.ops.oracle:
|
||||||
# Should be able to execute the queries; however, they won't be the same
|
# Should be able to execute the queries; however, they won't be the same
|
||||||
# as GEOS (because Oracle doesn't use GEOS internally like PostGIS or
|
# as GEOS (because Oracle doesn't use GEOS internally like PostGIS or
|
||||||
# SpatiaLite).
|
# SpatiaLite).
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
from unittest import skipUnless
|
|
||||||
|
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.db.models import Index
|
from django.db.models import Index
|
||||||
from django.test import TransactionTestCase
|
from django.test import TransactionTestCase
|
||||||
|
|
||||||
from ..utils import mysql, oracle, postgis
|
|
||||||
from .models import City
|
from .models import City
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,17 +19,18 @@ class SchemaIndexesTests(TransactionTestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
def has_spatial_indexes(self, table):
|
def has_spatial_indexes(self, table):
|
||||||
if mysql:
|
if connection.ops.mysql:
|
||||||
with connection.cursor() as cursor:
|
with connection.cursor() as cursor:
|
||||||
return connection.introspection.supports_spatial_index(cursor, table)
|
return connection.introspection.supports_spatial_index(cursor, table)
|
||||||
elif oracle:
|
elif connection.ops.oracle:
|
||||||
# Spatial indexes in Meta.indexes are not supported by the Oracle
|
# Spatial indexes in Meta.indexes are not supported by the Oracle
|
||||||
# backend (see #31252).
|
# backend (see #31252).
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@skipUnless(postgis, 'This is a PostGIS-specific test.')
|
|
||||||
def test_using_sql(self):
|
def test_using_sql(self):
|
||||||
|
if not connection.ops.postgis:
|
||||||
|
self.skipTest('This is a PostGIS-specific test.')
|
||||||
index = Index(fields=['point'])
|
index = Index(fields=['point'])
|
||||||
editor = connection.schema_editor()
|
editor = connection.schema_editor()
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
|
|
|
@ -13,9 +13,7 @@ from django.db.models import F, OuterRef, Subquery
|
||||||
from django.test import TestCase, skipUnlessDBFeature
|
from django.test import TestCase, skipUnlessDBFeature
|
||||||
from django.test.utils import CaptureQueriesContext
|
from django.test.utils import CaptureQueriesContext
|
||||||
|
|
||||||
from ..utils import (
|
from ..utils import skipUnlessGISLookup
|
||||||
mariadb, mysql, oracle, postgis, skipUnlessGISLookup, spatialite,
|
|
||||||
)
|
|
||||||
from .models import (
|
from .models import (
|
||||||
City, Country, Feature, MinusOneSRID, MultiFields, NonConcreteModel,
|
City, Country, Feature, MinusOneSRID, MultiFields, NonConcreteModel,
|
||||||
PennsylvaniaCity, State, Track,
|
PennsylvaniaCity, State, Track,
|
||||||
|
@ -109,7 +107,7 @@ class GeoModelTest(TestCase):
|
||||||
# Constructing & querying with a point from a different SRID. Oracle
|
# Constructing & querying with a point from a different SRID. Oracle
|
||||||
# `SDO_OVERLAPBDYINTERSECT` operates differently from
|
# `SDO_OVERLAPBDYINTERSECT` operates differently from
|
||||||
# `ST_Intersects`, so contains is used instead.
|
# `ST_Intersects`, so contains is used instead.
|
||||||
if oracle:
|
if connection.ops.oracle:
|
||||||
tx = Country.objects.get(mpoly__contains=other_srid_pnt)
|
tx = Country.objects.get(mpoly__contains=other_srid_pnt)
|
||||||
else:
|
else:
|
||||||
tx = Country.objects.get(mpoly__intersects=other_srid_pnt)
|
tx = Country.objects.get(mpoly__intersects=other_srid_pnt)
|
||||||
|
@ -299,7 +297,7 @@ class GeoLookupTest(TestCase):
|
||||||
invalid_geom = fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 1 1, 1 0, 0 0))')
|
invalid_geom = fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 1 1, 1 0, 0 0))')
|
||||||
State.objects.create(name='invalid', poly=invalid_geom)
|
State.objects.create(name='invalid', poly=invalid_geom)
|
||||||
qs = State.objects.all()
|
qs = State.objects.all()
|
||||||
if oracle or (mysql and connection.mysql_version < (8, 0, 0)):
|
if connection.ops.oracle or (connection.ops.mysql and connection.mysql_version < (8, 0, 0)):
|
||||||
# Kansas has adjacent vertices with distance 6.99244813842e-12
|
# Kansas has adjacent vertices with distance 6.99244813842e-12
|
||||||
# which is smaller than the default Oracle tolerance.
|
# which is smaller than the default Oracle tolerance.
|
||||||
# It's invalid on MySQL < 8 also.
|
# It's invalid on MySQL < 8 also.
|
||||||
|
@ -453,12 +451,11 @@ class GeoLookupTest(TestCase):
|
||||||
with self.assertRaises(e):
|
with self.assertRaises(e):
|
||||||
qs.count()
|
qs.count()
|
||||||
|
|
||||||
# Relate works differently for the different backends.
|
contains_mask = 'T*T***FF*'
|
||||||
if postgis or spatialite or mariadb:
|
within_mask = 'T*F**F***'
|
||||||
contains_mask = 'T*T***FF*'
|
intersects_mask = 'T********'
|
||||||
within_mask = 'T*F**F***'
|
# Relate works differently on Oracle.
|
||||||
intersects_mask = 'T********'
|
if connection.ops.oracle:
|
||||||
elif oracle:
|
|
||||||
contains_mask = 'contains'
|
contains_mask = 'contains'
|
||||||
within_mask = 'inside'
|
within_mask = 'inside'
|
||||||
# TODO: This is not quite the same as the PostGIS mask above
|
# TODO: This is not quite the same as the PostGIS mask above
|
||||||
|
@ -477,7 +474,7 @@ class GeoLookupTest(TestCase):
|
||||||
self.assertEqual('Lawrence', City.objects.get(point__relate=(ks.poly, within_mask)).name)
|
self.assertEqual('Lawrence', City.objects.get(point__relate=(ks.poly, within_mask)).name)
|
||||||
|
|
||||||
# Testing intersection relation mask.
|
# Testing intersection relation mask.
|
||||||
if not oracle:
|
if not connection.ops.oracle:
|
||||||
if connection.features.supports_transform:
|
if connection.features.supports_transform:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
Country.objects.get(mpoly__relate=(pnt1, intersects_mask)).name,
|
Country.objects.get(mpoly__relate=(pnt1, intersects_mask)).name,
|
||||||
|
@ -487,7 +484,7 @@ class GeoLookupTest(TestCase):
|
||||||
self.assertEqual('Lawrence', City.objects.get(point__relate=(ks.poly, intersects_mask)).name)
|
self.assertEqual('Lawrence', City.objects.get(point__relate=(ks.poly, intersects_mask)).name)
|
||||||
|
|
||||||
# With a complex geometry expression
|
# With a complex geometry expression
|
||||||
mask = 'anyinteract' if oracle else within_mask
|
mask = 'anyinteract' if connection.ops.oracle else within_mask
|
||||||
self.assertFalse(City.objects.exclude(point__relate=(functions.Union('point', 'point'), mask)))
|
self.assertFalse(City.objects.exclude(point__relate=(functions.Union('point', 'point'), mask)))
|
||||||
|
|
||||||
def test_gis_lookups_with_complex_expressions(self):
|
def test_gis_lookups_with_complex_expressions(self):
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
Tests for geography support in PostGIS
|
Tests for geography support in PostGIS
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
from unittest import skipUnless
|
|
||||||
|
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
from django.contrib.gis.db.models.functions import Area, Distance
|
from django.contrib.gis.db.models.functions import Area, Distance
|
||||||
|
@ -11,7 +10,7 @@ from django.db import NotSupportedError, connection
|
||||||
from django.db.models.functions import Cast
|
from django.db.models.functions import Cast
|
||||||
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
|
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
|
||||||
|
|
||||||
from ..utils import FuncTestMixin, oracle, postgis, spatialite
|
from ..utils import FuncTestMixin
|
||||||
from .models import City, County, Zipcode
|
from .models import City, County, Zipcode
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,9 +36,10 @@ class GeographyTest(TestCase):
|
||||||
for cities in [cities1, cities2]:
|
for cities in [cities1, cities2]:
|
||||||
self.assertEqual(['Dallas', 'Houston', 'Oklahoma City'], cities)
|
self.assertEqual(['Dallas', 'Houston', 'Oklahoma City'], cities)
|
||||||
|
|
||||||
@skipUnless(postgis, "This is a PostGIS-specific test")
|
|
||||||
def test04_invalid_operators_functions(self):
|
def test04_invalid_operators_functions(self):
|
||||||
"Ensuring exceptions are raised for operators & functions invalid on geography fields."
|
"Ensuring exceptions are raised for operators & functions invalid on geography fields."
|
||||||
|
if not connection.ops.postgis:
|
||||||
|
self.skipTest('This is a PostGIS-specific test.')
|
||||||
# Only a subset of the geometry functions & operator are available
|
# Only a subset of the geometry functions & operator are available
|
||||||
# to PostGIS geography types. For more information, visit:
|
# to PostGIS geography types. For more information, visit:
|
||||||
# http://postgis.refractions.net/documentation/manual-1.5/ch08.html#PostGIS_GeographyFunctions
|
# http://postgis.refractions.net/documentation/manual-1.5/ch08.html#PostGIS_GeographyFunctions
|
||||||
|
@ -108,9 +108,9 @@ class GeographyFunctionTests(FuncTestMixin, TestCase):
|
||||||
"""
|
"""
|
||||||
Testing Distance() support on non-point geography fields.
|
Testing Distance() support on non-point geography fields.
|
||||||
"""
|
"""
|
||||||
if oracle:
|
if connection.ops.oracle:
|
||||||
ref_dists = [0, 4899.68, 8081.30, 9115.15]
|
ref_dists = [0, 4899.68, 8081.30, 9115.15]
|
||||||
elif spatialite:
|
elif connection.ops.spatialite:
|
||||||
# SpatiaLite returns non-zero distance for polygons and points
|
# SpatiaLite returns non-zero distance for polygons and points
|
||||||
# covered by that polygon.
|
# covered by that polygon.
|
||||||
ref_dists = [326.61, 4899.68, 8081.30, 9115.15]
|
ref_dists = [326.61, 4899.68, 8081.30, 9115.15]
|
||||||
|
@ -124,13 +124,13 @@ class GeographyFunctionTests(FuncTestMixin, TestCase):
|
||||||
for z, ref in zip(qs, ref_dists):
|
for z, ref in zip(qs, ref_dists):
|
||||||
self.assertAlmostEqual(z.distance.m, ref, 2)
|
self.assertAlmostEqual(z.distance.m, ref, 2)
|
||||||
|
|
||||||
if postgis:
|
if connection.ops.postgis:
|
||||||
# PostGIS casts geography to geometry when distance2 is calculated.
|
# PostGIS casts geography to geometry when distance2 is calculated.
|
||||||
ref_dists = [0, 4899.68, 8081.30, 9115.15]
|
ref_dists = [0, 4899.68, 8081.30, 9115.15]
|
||||||
for z, ref in zip(qs, ref_dists):
|
for z, ref in zip(qs, ref_dists):
|
||||||
self.assertAlmostEqual(z.distance2.m, ref, 2)
|
self.assertAlmostEqual(z.distance2.m, ref, 2)
|
||||||
|
|
||||||
if not spatialite:
|
if not connection.ops.spatialite:
|
||||||
# Distance function combined with a lookup.
|
# Distance function combined with a lookup.
|
||||||
hzip = Zipcode.objects.get(code='77002')
|
hzip = Zipcode.objects.get(code='77002')
|
||||||
self.assertEqual(qs.get(distance__lte=0), hzip)
|
self.assertEqual(qs.get(distance__lte=0), hzip)
|
||||||
|
|
|
@ -10,8 +10,6 @@ from django.test import (
|
||||||
TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature,
|
TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature,
|
||||||
)
|
)
|
||||||
|
|
||||||
from ..utils import mysql, oracle
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
GeometryColumns = connection.ops.geometry_columns()
|
GeometryColumns = connection.ops.geometry_columns()
|
||||||
HAS_GEOMETRY_COLUMNS = True
|
HAS_GEOMETRY_COLUMNS = True
|
||||||
|
@ -30,7 +28,7 @@ class OperationTestCase(TransactionTestCase):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_spatial_indexes(self):
|
def has_spatial_indexes(self):
|
||||||
if mysql:
|
if connection.ops.mysql:
|
||||||
with connection.cursor() as cursor:
|
with connection.cursor() as cursor:
|
||||||
return connection.introspection.supports_spatial_index(cursor, 'gis_neighborhood')
|
return connection.introspection.supports_spatial_index(cursor, 'gis_neighborhood')
|
||||||
return True
|
return True
|
||||||
|
@ -120,7 +118,7 @@ class OperationTests(OperationTestCase):
|
||||||
def test_geom_col_name(self):
|
def test_geom_col_name(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
GeometryColumns.geom_col_name(),
|
GeometryColumns.geom_col_name(),
|
||||||
'column_name' if oracle else 'f_geometry_column',
|
'column_name' if connection.ops.oracle else 'f_geometry_column',
|
||||||
)
|
)
|
||||||
|
|
||||||
@skipUnlessDBFeature('supports_raster')
|
@skipUnlessDBFeature('supports_raster')
|
||||||
|
|
|
@ -10,7 +10,6 @@ from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
|
||||||
from django.test.utils import modify_settings
|
from django.test.utils import modify_settings
|
||||||
|
|
||||||
from ..test_data import TEST_DATA
|
from ..test_data import TEST_DATA
|
||||||
from ..utils import mariadb
|
|
||||||
from .models import AllOGRFields
|
from .models import AllOGRFields
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,7 +141,7 @@ class OGRInspectTest(SimpleTestCase):
|
||||||
else:
|
else:
|
||||||
self.assertIn(' f_decimal = models.DecimalField(max_digits=0, decimal_places=0)', model_def)
|
self.assertIn(' f_decimal = models.DecimalField(max_digits=0, decimal_places=0)', model_def)
|
||||||
self.assertIn(' f_int = models.IntegerField()', model_def)
|
self.assertIn(' f_int = models.IntegerField()', model_def)
|
||||||
if not mariadb:
|
if not connection.ops.mariadb:
|
||||||
# Probably a bug between GDAL and MariaDB on time fields.
|
# Probably a bug between GDAL and MariaDB on time fields.
|
||||||
self.assertIn(' f_datetime = models.DateTimeField()', model_def)
|
self.assertIn(' f_datetime = models.DateTimeField()', model_def)
|
||||||
self.assertIn(' f_time = models.TimeField()', model_def)
|
self.assertIn(' f_time = models.TimeField()', model_def)
|
||||||
|
|
|
@ -4,8 +4,6 @@ from django.db import connection
|
||||||
from django.test import TestCase, skipUnlessDBFeature
|
from django.test import TestCase, skipUnlessDBFeature
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
from .utils import oracle, postgis, spatialite
|
|
||||||
|
|
||||||
test_srs = ({
|
test_srs = ({
|
||||||
'srid': 4326,
|
'srid': 4326,
|
||||||
'auth_name': ('EPSG', True),
|
'auth_name': ('EPSG', True),
|
||||||
|
@ -75,13 +73,15 @@ class SpatialRefSysTest(TestCase):
|
||||||
# also, Oracle Spatial seems to add extraneous info to fields, hence the
|
# also, Oracle Spatial seems to add extraneous info to fields, hence the
|
||||||
# the testing with the 'startswith' flag.
|
# the testing with the 'startswith' flag.
|
||||||
auth_name, oracle_flag = sd['auth_name']
|
auth_name, oracle_flag = sd['auth_name']
|
||||||
if postgis or (oracle and oracle_flag):
|
# Compare case-insensitively because srs.auth_name is lowercase
|
||||||
self.assertTrue(srs.auth_name.startswith(auth_name))
|
# ("epsg") on Spatialite.
|
||||||
|
if not connection.ops.oracle or oracle_flag:
|
||||||
|
self.assertIs(srs.auth_name.upper().startswith(auth_name), True)
|
||||||
|
|
||||||
self.assertEqual(sd['auth_srid'], srs.auth_srid)
|
self.assertEqual(sd['auth_srid'], srs.auth_srid)
|
||||||
|
|
||||||
# No PROJ and different srtext on oracle backends :(
|
# No PROJ and different srtext on Oracle.
|
||||||
if postgis:
|
if not connection.ops.oracle:
|
||||||
self.assertTrue(srs.wkt.startswith(sd['srtext']))
|
self.assertTrue(srs.wkt.startswith(sd['srtext']))
|
||||||
self.assertRegex(srs.proj4text, sd['proj_re'])
|
self.assertRegex(srs.proj4text, sd['proj_re'])
|
||||||
|
|
||||||
|
@ -94,14 +94,9 @@ class SpatialRefSysTest(TestCase):
|
||||||
self.assertTrue(sr.spheroid.startswith(sd['spheroid']))
|
self.assertTrue(sr.spheroid.startswith(sd['spheroid']))
|
||||||
self.assertEqual(sd['geographic'], sr.geographic)
|
self.assertEqual(sd['geographic'], sr.geographic)
|
||||||
self.assertEqual(sd['projected'], sr.projected)
|
self.assertEqual(sd['projected'], sr.projected)
|
||||||
|
self.assertIs(sr.name.startswith(sd['name']), True)
|
||||||
if not (spatialite and not sd['spatialite']):
|
|
||||||
# Can't get 'NAD83 / Texas South Central' from PROJ string
|
|
||||||
# on SpatiaLite
|
|
||||||
self.assertTrue(sr.name.startswith(sd['name']))
|
|
||||||
|
|
||||||
# Testing the SpatialReference object directly.
|
# Testing the SpatialReference object directly.
|
||||||
if postgis or spatialite:
|
if not connection.ops.oracle:
|
||||||
srs = sr.srs
|
srs = sr.srs
|
||||||
self.assertRegex(srs.proj, sd['proj_re'])
|
self.assertRegex(srs.proj, sd['proj_re'])
|
||||||
self.assertTrue(srs.wkt.startswith(sd['srtext']))
|
self.assertTrue(srs.wkt.startswith(sd['srtext']))
|
||||||
|
|
|
@ -24,16 +24,9 @@ def skipUnlessGISLookup(*gis_lookups):
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
# Shortcut booleans to omit only portions of tests.
|
|
||||||
_default_db = settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'].rsplit('.')[-1]
|
_default_db = settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'].rsplit('.')[-1]
|
||||||
oracle = _default_db == 'oracle'
|
|
||||||
postgis = _default_db == 'postgis'
|
|
||||||
mysql = _default_db == 'mysql'
|
|
||||||
mariadb = mysql and connection.mysql_is_mariadb
|
|
||||||
spatialite = _default_db == 'spatialite'
|
|
||||||
|
|
||||||
# MySQL spatial indices can't handle NULL geometries.
|
# MySQL spatial indices can't handle NULL geometries.
|
||||||
gisfield_may_be_null = not mysql
|
gisfield_may_be_null = _default_db != 'mysql'
|
||||||
|
|
||||||
|
|
||||||
class FuncTestMixin:
|
class FuncTestMixin:
|
||||||
|
|
Loading…
Reference in New Issue