Skip to content

Commit 2228431

Browse files
committed
refactor index deletion
1 parent 6dc0b3c commit 2228431

File tree

1 file changed

+22
-140
lines changed

1 file changed

+22
-140
lines changed

django_mongodb/schema.py

Lines changed: 22 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from django.core.exceptions import FieldError
21
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
32
from django.db.models import Index
43
from pymongo.operations import IndexModel
@@ -58,91 +57,25 @@ def add_field(self, model, field):
5857
index.name = self._create_index_name(model._meta.db_table, [field.column])
5958
self.add_index(model, index, field=field)
6059

61-
def alter_field(self, model, old_field, new_field, strict=False, old_db_table=None):
62-
"""
63-
Allow a field's type, uniqueness, nullability, default, column,
64-
constraints, etc. to be modified.
65-
`old_field` is required to compute the necessary changes.
66-
If `strict` is True, raise errors if the old column does not match
67-
`old_field` precisely.
68-
69-
This is identical to the base class except `old_db_table` is added.
70-
"""
71-
if not self._field_should_be_altered(old_field, new_field):
72-
return
73-
# Ensure this field is even column-based
74-
old_db_params = old_field.db_parameters(connection=self.connection)
75-
old_type = old_db_params["type"]
76-
new_db_params = new_field.db_parameters(connection=self.connection)
77-
new_type = new_db_params["type"]
78-
modifying_generated_field = False
79-
if (old_type is None and old_field.remote_field is None) or (
80-
new_type is None and new_field.remote_field is None
81-
):
82-
raise ValueError(
83-
f"Cannot alter field {old_field} into {new_field} - they do "
84-
"not properly define db_type (are you using a badly-written "
85-
"custom field?)"
86-
)
87-
if (
88-
old_type is None
89-
and new_type is None
90-
and (
91-
old_field.remote_field.through
92-
and new_field.remote_field.through
93-
and old_field.remote_field.through._meta.auto_created
94-
and new_field.remote_field.through._meta.auto_created
95-
)
96-
):
97-
self._alter_many_to_many(model, old_field, new_field, strict)
98-
return
99-
if (
100-
old_type is None
101-
and new_type is None
102-
and (
103-
old_field.remote_field.through
104-
and new_field.remote_field.through
105-
and not old_field.remote_field.through._meta.auto_created
106-
and not new_field.remote_field.through._meta.auto_created
107-
)
108-
):
109-
# Both sides have through models; this is a no-op.
110-
return
111-
if old_type is None or new_type is None:
112-
raise ValueError(
113-
f"Cannot alter field {old_field} into {new_field} - they are "
114-
"not compatible types (you cannot alter to or from M2M fields, "
115-
"or add or remove through= on M2M fields)"
116-
)
117-
if old_field.generated != new_field.generated or (
118-
new_field.generated and old_field.db_persist != new_field.db_persist
119-
):
120-
modifying_generated_field = True
121-
elif new_field.generated:
122-
try:
123-
old_field_sql = old_field.generated_sql(self.connection)
124-
except FieldError:
125-
# Field used in a generated field was renamed.
126-
modifying_generated_field = True
127-
else:
128-
new_field_sql = new_field.generated_sql(self.connection)
129-
modifying_generated_field = old_field_sql != new_field_sql
130-
if modifying_generated_field:
131-
raise ValueError(
132-
f"Modifying GeneratedFields is not supported - the field {new_field} "
133-
"must be removed and re-added with the new definition."
134-
)
135-
self._alter_field(
60+
def _drop_index_for_field(self, collection, model, field):
61+
# Find the index for this field
62+
meta_index_names = {index.name for index in model._meta.indexes}
63+
# Retrieve only BTREE indexes since this is what's created with
64+
# db_index=True.
65+
index_names = self._constraint_names(
13666
model,
137-
old_field,
138-
new_field,
139-
old_type,
140-
new_type,
141-
old_db_params,
142-
new_db_params,
143-
strict,
144-
old_db_table,
67+
[field.column],
68+
index=True,
69+
type_=Index.suffix,
70+
exclude=meta_index_names,
14571
)
72+
if not index_names:
73+
raise ValueError(f"Index not found for {model._meta.db_table}.{field.column}.")
74+
for index_name in index_names:
75+
# The only way to check if an index was created with
76+
# db_index=True or with Index(['field'], name='foo')
77+
# is to look at its name (refs #28053).
78+
collection.drop_index(index_name)
14679

14780
def _alter_field(
14881
self,
@@ -154,7 +87,6 @@ def _alter_field(
15487
old_db_params,
15588
new_db_params,
15689
strict=False,
157-
old_db_table=None,
15890
):
15991
collection = self.connection.database[model._meta.db_table]
16092
# Removed an index? (no strict check, as multiple indexes are possible)
@@ -172,31 +104,15 @@ def _alter_field(
172104
and not old_field.unique
173105
and (not new_field.db_index or new_field.unique)
174106
):
175-
# Find the index for this field
176-
meta_index_names = {index.name for index in model._meta.indexes}
177-
# Retrieve only BTREE indexes since this is what's created with
178-
# db_index=True.
179-
index_names = self._constraint_names(
180-
model,
181-
[old_field.column],
182-
index=True,
183-
type_=Index.suffix,
184-
exclude=meta_index_names,
185-
)
186-
for index_name in index_names:
187-
# The only way to check if an index was created with
188-
# db_index=True or with Index(['field'], name='foo')
189-
# is to look at its name (refs #28053).
190-
collection.drop_index(index_name)
107+
self._drop_index_for_field(collection, model, old_field)
191108
# Have they renamed the column?
192109
if old_field.column != new_field.column:
193110
collection.update_many({}, {"$rename": {old_field.column: new_field.column}})
194111
# Move index to the new field, if needed.
195-
if old_field.db_index and new_field.db_index:
196-
old_db_table = old_db_table or model._meta.db_table
197-
old_index = Index(fields=[old_field.name])
198-
old_index.name = self._create_index_name(old_db_table, [old_field.column])
199-
self.remove_index(model, old_index)
112+
if self._field_should_be_indexed(model, old_field) and self.__field_should_be_indexed(
113+
model, new_field
114+
):
115+
self._drop_index_for_field(collection, model, old_field)
200116
new_index = Index(fields=[new_field.name])
201117
new_index.name = self._create_index_name(model._meta.db_table, [new_field.column])
202118
self.add_index(model, new_index, field=new_field)
@@ -224,40 +140,6 @@ def _alter_field(
224140
index.name = self._create_index_name(model._meta.db_table, [new_field.column])
225141
self.add_index(model, index)
226142

227-
def _alter_many_to_many(self, model, old_field, new_field, strict):
228-
"""
229-
Alter M2Ms to repoint their to= endpoints.
230-
231-
This is identical to the base class except `old_db_table=...` is added.
232-
"""
233-
# Rename the through table
234-
if (
235-
old_field.remote_field.through._meta.db_table
236-
!= new_field.remote_field.through._meta.db_table
237-
):
238-
self.alter_db_table(
239-
old_field.remote_field.through,
240-
old_field.remote_field.through._meta.db_table,
241-
new_field.remote_field.through._meta.db_table,
242-
)
243-
# Repoint the FK to the other side
244-
self.alter_field(
245-
new_field.remote_field.through,
246-
# The field that points to the target model is needed, so we can
247-
# tell alter_field to change it - this is m2m_reverse_field_name()
248-
# (as opposed to m2m_field_name(), which points to our model).
249-
old_field.remote_field.through._meta.get_field(old_field.m2m_reverse_field_name()),
250-
new_field.remote_field.through._meta.get_field(new_field.m2m_reverse_field_name()),
251-
old_db_table=old_field.remote_field.through._meta.db_table,
252-
)
253-
self.alter_field(
254-
new_field.remote_field.through,
255-
# for self-referential models we need to alter field from the other end too
256-
old_field.remote_field.through._meta.get_field(old_field.m2m_field_name()),
257-
new_field.remote_field.through._meta.get_field(new_field.m2m_field_name()),
258-
old_db_table=old_field.remote_field.through._meta.db_table,
259-
)
260-
261143
def remove_field(self, model, field):
262144
# Remove implicit M2M tables.
263145
if field.many_to_many and field.remote_field.through._meta.auto_created:

0 commit comments

Comments
 (0)