Skip to content

Commit 9c55bfa

Browse files
committed
Add support for GeoSpatial indexes
1 parent 8b57307 commit 9c55bfa

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

django_mongodb_backend/introspection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from django.db.backends.base.introspection import BaseDatabaseIntrospection
22
from django.db.models import Index
3-
from pymongo import ASCENDING, DESCENDING
3+
from pymongo import ASCENDING, DESCENDING, GEOSPHERE
44

55
from django_mongodb_backend.indexes import SearchIndex, VectorSearchIndex
66

77

88
class DatabaseIntrospection(BaseDatabaseIntrospection):
9-
ORDER_DIR = {ASCENDING: "ASC", DESCENDING: "DESC"}
9+
ORDER_DIR = {ASCENDING: "ASC", DESCENDING: "DESC", GEOSPHERE: "GEO"}
1010

1111
def table_names(self, cursor=None, include_views=False):
1212
return sorted([x["name"] for x in self.connection.database.list_collections()])

django_mongodb_backend_gis/schema.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,67 @@
1+
from django.contrib.gis.db.models import GeometryField
2+
from pymongo import GEOSPHERE
3+
from pymongo.operations import IndexModel
4+
15
from django_mongodb_backend.schema import DatabaseSchemaEditor as BaseSchemaEditor
26

37

48
class DatabaseSchemaEditor(BaseSchemaEditor):
5-
pass
9+
def _field_should_be_indexed(self, model, field):
10+
if getattr(field, "spatial_index", False):
11+
return True
12+
return super()._field_should_be_indexed(model, field)
13+
14+
def _add_field_index(self, model, field, *, column_prefix=""):
15+
if hasattr(field, "geodetic"):
16+
self._add_spatial_index(model, field)
17+
else:
18+
super()._add_field_index(model, field, column_prefix=column_prefix)
19+
20+
def _alter_field(
21+
self,
22+
model,
23+
old_field,
24+
new_field,
25+
old_type,
26+
new_type,
27+
old_db_params,
28+
new_db_params,
29+
strict=False,
30+
):
31+
super()._alter_field(
32+
model,
33+
old_field,
34+
new_field,
35+
old_type,
36+
new_type,
37+
old_db_params,
38+
new_db_params,
39+
strict=strict,
40+
)
41+
42+
old_field_spatial_index = isinstance(old_field, GeometryField) and old_field.spatial_index
43+
new_field_spatial_index = isinstance(new_field, GeometryField) and new_field.spatial_index
44+
if not old_field_spatial_index and new_field_spatial_index:
45+
self._add_spatial_index(model, new_field)
46+
elif old_field_spatial_index and not new_field_spatial_index:
47+
self._delete_spatial_index(model, new_field)
48+
49+
def _add_spatial_index(self, model, field):
50+
index_name = self._create_spatial_index_name(model, field)
51+
self.get_collection(model._meta.db_table).create_indexes(
52+
[
53+
IndexModel(
54+
[
55+
(field.column, GEOSPHERE),
56+
],
57+
name=index_name,
58+
)
59+
]
60+
)
61+
62+
def _delete_spatial_index(self, model, field):
63+
index_name = self._create_spatial_index_name(model, field)
64+
self.get_collection(model._meta.db_table).drop_index(index_name)
65+
66+
def _create_spatial_index_name(self, model, field):
67+
return f"{model._meta.db_table}_{field.column}_id"

0 commit comments

Comments
 (0)