Skip to content

Commit b195687

Browse files
committed
implement SchemaEditor.add/remove_index() and creating indexes in create_model()
1 parent da7eee1 commit b195687

File tree

3 files changed

+66
-32
lines changed

3 files changed

+66
-32
lines changed

django_mongodb/features.py

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -84,29 +84,14 @@ class DatabaseFeatures(BaseDatabaseFeatures):
8484
"backends.tests.ThreadTests.test_pass_connection_between_threads",
8585
"backends.tests.ThreadTests.test_closing_non_shared_connections",
8686
"backends.tests.ThreadTests.test_default_connection_thread_local",
87-
# Add/RemoveIndex
88-
"migrations.test_operations.OperationTests.test_add_index",
89-
"migrations.test_operations.OperationTests.test_alter_field_with_index",
90-
"migrations.test_operations.OperationTests.test_remove_index",
91-
"migrations.test_operations.OperationTests.test_rename_index",
92-
"migrations.test_operations.OperationTests.test_rename_index_unknown_unnamed_index",
93-
"migrations.test_operations.OperationTests.test_rename_index_unnamed_index",
94-
"schema.tests.SchemaTests.test_add_remove_index",
95-
"schema.tests.SchemaTests.test_composed_desc_index_with_fk",
96-
"schema.tests.SchemaTests.test_composed_index_with_fk",
97-
"schema.tests.SchemaTests.test_create_index_together",
98-
"schema.tests.SchemaTests.test_order_index",
99-
"schema.tests.SchemaTests.test_text_field_with_db_index",
10087
# AlterField
10188
"schema.tests.SchemaTests.test_alter_auto_field_to_integer_field",
10289
"schema.tests.SchemaTests.test_alter_field_add_index_to_integerfield",
10390
"schema.tests.SchemaTests.test_alter_field_default_dropped",
104-
"schema.tests.SchemaTests.test_alter_field_fk_keeps_index",
10591
"schema.tests.SchemaTests.test_alter_field_fk_to_o2o",
10692
"schema.tests.SchemaTests.test_alter_field_o2o_keeps_unique",
10793
"schema.tests.SchemaTests.test_alter_field_o2o_to_fk",
10894
"schema.tests.SchemaTests.test_alter_int_pk_to_int_unique",
109-
"schema.tests.SchemaTests.test_alter_not_unique_field_to_primary_key",
11095
"schema.tests.SchemaTests.test_alter_null_to_not_null",
11196
"schema.tests.SchemaTests.test_alter_primary_key_the_same_name",
11297
"schema.tests.SchemaTests.test_autofield_to_o2o",
@@ -124,21 +109,17 @@ class DatabaseFeatures(BaseDatabaseFeatures):
124109
"migrations.test_operations.OperationTests.test_alter_unique_together",
125110
"schema.tests.SchemaTests.test_unique_together",
126111
# add/remove_constraint
112+
"introspection.tests.IntrospectionTests.test_get_constraints",
127113
"migrations.test_operations.OperationTests.test_add_partial_unique_constraint",
128114
"migrations.test_operations.OperationTests.test_create_model_with_partial_unique_constraint",
129115
"migrations.test_operations.OperationTests.test_remove_partial_unique_constraint",
130116
"schema.tests.SchemaTests.test_composed_constraint_with_fk",
131117
"schema.tests.SchemaTests.test_remove_ignored_unique_constraint_not_create_fk_index",
132118
"schema.tests.SchemaTests.test_unique_constraint",
133-
# constraints not fully implemented.
134-
"introspection.tests.IntrospectionTests.test_get_constraints",
135119
# pymongo.errors.OperationFailure: Can't rename a collection to itself
136120
"migrations.test_operations.OperationTests.test_alter_model_table_noop",
137121
"migrations.test_operations.OperationTests.test_rename_model_no_relations_with_db_table_noop",
138122
"migrations.test_operations.OperationTests.test_rename_model_with_db_table_rename_m2m",
139-
# subclasses of BaseDatabaseIntrospection may require a get_constraints() method
140-
"migrations.test_operations.OperationTests.test_add_func_unique_constraint",
141-
"migrations.test_operations.OperationTests.test_remove_func_unique_constraint",
142123
}
143124
# $bitAnd, #bitOr, and $bitXor are new in MongoDB 6.3.
144125
_django_test_expected_failures_bitwise = {
@@ -241,6 +222,7 @@ def django_test_expected_failures(self):
241222
"get_or_create.tests.GetOrCreateThroughManyToMany.test_something",
242223
"get_or_create.tests.UpdateOrCreateTests.test_manual_primary_key_test",
243224
"get_or_create.tests.UpdateOrCreateTestsWithManualPKs.test_create_with_duplicate_primary_key",
225+
"introspection.tests.IntrospectionTests.test_get_constraints_unique_indexes_orders",
244226
"model_fields.test_filefield.FileFieldTests.test_unique_when_same_filename",
245227
"one_to_one.tests.OneToOneTests.test_multiple_o2o",
246228
"queries.test_bulk_update.BulkUpdateTests.test_database_routing_batch_atomicity",
@@ -624,14 +606,8 @@ def django_test_expected_failures(self):
624606
"introspection.tests.IntrospectionTests.test_get_table_description_types",
625607
"introspection.tests.IntrospectionTests.test_smallautofield",
626608
},
627-
"DatabaseIntrospection.get_constraints() not implemented.": {
628-
"introspection.tests.IntrospectionTests.test_get_constraints",
629-
"introspection.tests.IntrospectionTests.test_get_constraints_index_types",
630-
"introspection.tests.IntrospectionTests.test_get_constraints_indexes_orders",
631-
"introspection.tests.IntrospectionTests.test_get_constraints_unique_indexes_orders",
632-
"introspection.tests.IntrospectionTests.test_get_primary_key_column",
633-
},
634609
"MongoDB can't introspect primary key.": {
610+
"introspection.tests.IntrospectionTests.test_get_primary_key_column",
635611
"schema.tests.SchemaTests.test_primary_key",
636612
},
637613
"Known issue querying JSONField.": {

django_mongodb/introspection.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,31 @@
11
from django.db.backends.base.introspection import BaseDatabaseIntrospection
2+
from django.db.models import Index
23

34

45
class DatabaseIntrospection(BaseDatabaseIntrospection):
6+
ORDER_DIR = {1: "ASC", -1: "DESC"}
7+
58
def table_names(self, cursor=None, include_views=False):
69
return sorted([x["name"] for x in self.connection.database.list_collections()])
10+
11+
def get_constraints(self, cursor, table_name):
12+
indexes = self.connection.database[table_name].index_information()
13+
constraints = {}
14+
for name, details in indexes.items():
15+
# Remove underscore prefix from "_id" columns in primary key index.
16+
if is_primary_key := name == "_id_":
17+
name = "id"
18+
details["key"] = [("id", 1)]
19+
constraints[name] = {
20+
"check": False,
21+
"columns": [field for field, order in details["key"]],
22+
"definition": None,
23+
"foreign_key": None,
24+
"index": True,
25+
"orders": [self.ORDER_DIR[order] for field, order in details["key"]],
26+
"primary_key": is_primary_key,
27+
"type": Index.suffix,
28+
"unique": details.get("unique", False),
29+
"options": {},
30+
}
31+
return constraints

django_mongodb/schema.py

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,39 @@
11
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
2+
from django.db.models import Index
3+
from pymongo.operations import IndexModel
24

35

46
class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
57
def create_model(self, model):
68
self.connection.database.create_collection(model._meta.db_table)
9+
self._create_model_indexes(model)
710
# Make implicit M2M tables.
811
for field in model._meta.local_many_to_many:
912
if field.remote_field.through._meta.auto_created:
1013
self.create_model(field.remote_field.through)
1114

15+
def _create_model_indexes(self, model):
16+
"""
17+
Create all indexes (field indexes, index_together, Meta.indexes) for
18+
the specified model.
19+
"""
20+
if not model._meta.managed or model._meta.proxy or model._meta.swapped:
21+
return
22+
# Field indexes
23+
for field in model._meta.local_fields:
24+
if self._field_should_be_indexed(model, field):
25+
index = Index(fields=[field.name])
26+
index.set_name_with_model(model)
27+
self.add_index(model, index)
28+
# Meta.index_together (RemovedInDjango51Warning)
29+
for field_names in model._meta.index_together:
30+
index = Index(fields=field_names)
31+
index.set_name_with_model(model)
32+
self.add_index(model, index)
33+
# Meta.indexes
34+
for index in model._meta.indexes:
35+
self.add_index(model, index)
36+
1237
def delete_model(self, model):
1338
# Delete implicit M2m tables.
1439
for field in model._meta.local_many_to_many:
@@ -60,13 +85,21 @@ def alter_unique_together(self, model, old_unique_together, new_unique_together)
6085
pass
6186

6287
def add_index(self, model, index):
63-
pass
64-
65-
def rename_index(self, model, old_index, new_index):
66-
pass
88+
if index.contains_expressions:
89+
return
90+
idx = IndexModel(
91+
[
92+
(model._meta.get_field(field_name).column, 1 if order == "" else -1)
93+
for field_name, order in index.fields_orders
94+
],
95+
name=index.name,
96+
)
97+
self.connection.database[model._meta.db_table].create_indexes([idx])
6798

6899
def remove_index(self, model, index):
69-
pass
100+
if index.contains_expressions:
101+
return
102+
self.connection.database[model._meta.db_table].drop_index(index.name)
70103

71104
def add_constraint(self, model, constraint):
72105
pass

0 commit comments

Comments
 (0)