Removed redundant database vendor helpers in gis_tests/utils.py.

This commit is contained in:
Tim Graham 2020-11-14 09:08:30 -05:00 committed by Mariusz Felisiak
parent 9f91122ed8
commit e3ece0144a
12 changed files with 71 additions and 88 deletions

View File

@ -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

View File

@ -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)'

View File

@ -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)

View File

@ -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

View File

@ -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).

View File

@ -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(

View File

@ -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):

View File

@ -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)

View File

@ -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')

View File

@ -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)

View File

@ -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']))

View File

@ -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: