Skip to content

Commit a00d6df

Browse files
committed
Add GeoDjango support
1 parent 1471eca commit a00d6df

File tree

9 files changed

+184
-2
lines changed

9 files changed

+184
-2
lines changed

.github/workflows/test-python-atlas.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
- name: Install system packages for Django's Python test dependencies
4040
run: |
4141
sudo apt-get update
42-
sudo apt-get install libmemcached-dev
42+
sudo apt-get install gdal-bin libmemcached-dev
4343
- name: Install Django and its Python test dependencies
4444
run: |
4545
cd django_repo/tests/

.github/workflows/test-python.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
- name: Install system packages for Django's Python test dependencies
4040
run: |
4141
sudo apt-get update
42-
sudo apt-get install libmemcached-dev
42+
sudo apt-get install gdal-bin libmemcached-dev
4343
- name: Install Django and its Python test dependencies
4444
run: |
4545
cd django_repo/tests/
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .functions import register_functions
2+
3+
register_functions()

django_mongodb_backend_gis/adapter.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import collections
2+
3+
4+
class Adapter(collections.UserDict):
5+
def __init__(self, obj, geography=False):
6+
"""
7+
Initialize on the spatial object.
8+
"""
9+
self.data = {
10+
"type": obj.__class__.__name__,
11+
"coordinates": obj.coords,
12+
}

django_mongodb_backend_gis/base.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from django_mongodb_backend.base import DatabaseWrapper as BaseDatabaseWrapper
2+
3+
from .features import DatabaseFeatures
4+
from .operations import DatabaseOperations
5+
from .schema import DatabaseSchemaEditor
6+
7+
8+
class DatabaseWrapper(BaseDatabaseWrapper):
9+
SchemaEditorClass = DatabaseSchemaEditor
10+
features_class = DatabaseFeatures
11+
ops_class = DatabaseOperations
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from django.contrib.gis.db.backends.base.features import BaseSpatialFeatures
2+
from django.utils.functional import cached_property
3+
4+
from django_mongodb_backend.features import DatabaseFeatures as MongoFeatures
5+
6+
7+
class DatabaseFeatures(BaseSpatialFeatures, MongoFeatures):
8+
has_spatialrefsys_table = False
9+
supports_transform = False
10+
11+
@cached_property
12+
def django_test_expected_failures(self):
13+
expected_failures = super().django_test_expected_failures
14+
expected_failures.update(
15+
{
16+
# SRIDs aren't supported.
17+
"gis_tests.geogapp.tests.GeographyTest.test05_geography_layermapping",
18+
"gis_tests.geoapp.tests.GeoModelTest.test_proxy",
19+
# 'WithinLookup' object has no attribute 'as_mql'
20+
# "gis_tests.relatedapp.tests.RelatedGeoModelTest.test10_combine",
21+
# GEOSException: Calling transform() with no SRID set is not supported
22+
"gis_tests.relatedapp.tests.RelatedGeoModelTest.test06_f_expressions",
23+
# To triage:
24+
"gis_tests.geoapp.test_expressions.GeoExpressionsTests.test_geometry_value_annotation",
25+
"gis_tests.geoapp.test_expressions.GeoExpressionsTests.test_multiple_annotation",
26+
"gis_tests.geoapp.test_regress.GeoRegressionTests.test_empty_count",
27+
"gis_tests.geoapp.test_serializers.GeoJSONSerializerTests.test_fields_option",
28+
"gis_tests.geoapp.test_serializers.GeoJSONSerializerTests.test_geometry_field_option",
29+
"gis_tests.geoapp.test_serializers.GeoJSONSerializerTests.test_id_field_option",
30+
"gis_tests.geoapp.test_serializers.GeoJSONSerializerTests.test_serialization_base",
31+
"gis_tests.geoapp.test_serializers.GeoJSONSerializerTests.test_srid_option",
32+
"gis_tests.geoapp.tests.GeoLookupTest.test_contains_contained_lookups",
33+
"gis_tests.geoapp.tests.GeoLookupTest.test_disjoint_lookup",
34+
"gis_tests.geoapp.tests.GeoLookupTest.test_equals_lookups",
35+
"gis_tests.geoapp.tests.GeoLookupTest.test_null_geometries",
36+
"gis_tests.geoapp.tests.GeoLookupTest.test_subquery_annotation",
37+
"gis_tests.geoapp.tests.GeoModelTest.test_geometryfield",
38+
"gis_tests.geoapp.tests.GeoModelTest.test_gis_query_as_string",
39+
"gis_tests.geoapp.tests.GeoQuerySetTest.test_within_subquery",
40+
"gis_tests.geoapp.test_expressions.GeoExpressionsTests.test_update_from_other_field",
41+
# No lookups are supported (yet?)
42+
"gis_tests.geoapp.tests.GeoLookupTest.test_gis_lookups_with_complex_expressions",
43+
}
44+
)
45+
return expected_failures
46+
47+
@cached_property
48+
def django_test_skips(self):
49+
skips = super().django_test_skips
50+
skips.update(
51+
{
52+
"inspectdb not supported.": {
53+
"gis_tests.inspectapp.tests.InspectDbTests",
54+
},
55+
"Raw SQL not supported": {
56+
"gis_tests.geoapp.tests.GeoModelTest.test_raw_sql_query",
57+
},
58+
},
59+
)
60+
return skips
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Placeholder if we can support any functions.
2+
# from django.contrib.gis.db.models.functions import Distance, Length, Perimeter
3+
4+
5+
def register_functions():
6+
pass
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
from django.contrib.gis import geos
2+
from django.contrib.gis.db import models
3+
from django.contrib.gis.db.backends.base.operations import BaseSpatialOperations
4+
5+
from django_mongodb_backend.operations import (
6+
DatabaseOperations as MongoOperations,
7+
)
8+
9+
from .adapter import Adapter
10+
11+
12+
class DatabaseOperations(BaseSpatialOperations, MongoOperations):
13+
Adapter = Adapter
14+
15+
disallowed_aggregates = (
16+
models.Collect,
17+
models.Extent,
18+
models.Extent3D,
19+
models.MakeLine,
20+
models.Union,
21+
)
22+
23+
@property
24+
def gis_operators(self):
25+
return {}
26+
27+
unsupported_functions = {
28+
"Area",
29+
"AsGeoJSON",
30+
"AsGML",
31+
"AsKML",
32+
"AsSVG",
33+
"AsWKB",
34+
"AsWKT",
35+
"Azimuth",
36+
"BoundingCircle",
37+
"Centroid",
38+
"ClosestPoint",
39+
"Difference",
40+
"Distance",
41+
"Envelope",
42+
"ForcePolygonCW",
43+
"FromWKB",
44+
"FromWKT",
45+
"GeoHash",
46+
"GeometryDistance",
47+
"Intersection",
48+
"IsEmpty",
49+
"IsValid",
50+
"Length",
51+
"LineLocatePoint",
52+
"MakeValid",
53+
"MemSize",
54+
"NumGeometries",
55+
"NumPoints",
56+
"Perimeter",
57+
"PointOnSurface",
58+
"Reverse",
59+
"Scale",
60+
"SnapToGrid",
61+
"SymDifference",
62+
"Transform",
63+
"Translate",
64+
"Union",
65+
}
66+
67+
def geo_db_type(self, f):
68+
return "object"
69+
70+
def get_geometry_converter(self, expression):
71+
geom_class = expression.output_field.geom_class
72+
73+
def converter(value, expression, connection): # noqa: ARG001
74+
if value is None:
75+
return None
76+
if issubclass(geom_class, geos.GeometryCollection):
77+
init_val = [
78+
geom_class._allowed(value["coordinates"][x][0])
79+
for x in range(len(value["coordinates"]))
80+
]
81+
else:
82+
init_val = value["coordinates"]
83+
return geom_class(init_val)
84+
85+
return converter

django_mongodb_backend_gis/schema.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from django_mongodb_backend.schema import DatabaseSchemaEditor as BaseSchemaEditor
2+
3+
4+
class DatabaseSchemaEditor(BaseSchemaEditor):
5+
pass

0 commit comments

Comments
 (0)