Skip to content

Commit 566410e

Browse files
committed
wip
1 parent be8d467 commit 566410e

File tree

2 files changed

+194
-11
lines changed

2 files changed

+194
-11
lines changed

django_mongodb/schema.py

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ def add_field(self, model, field):
9797
self._create_model_indexes(
9898
field.embedded_model, parent_model=model, column_prefix=new_path
9999
)
100-
101100
# Add an index or unique, if required.
102101
if self._field_should_be_indexed(model, field):
103102
self._add_field_index(model, field)
@@ -162,13 +161,65 @@ def remove_field(self, model, field):
162161
self._remove_field_index(model, field)
163162
elif self._field_should_have_unique(field):
164163
self._remove_field_unique(model, field)
164+
if isinstance(field, EmbeddedModelField):
165+
new_path = f"{field.column}."
166+
self._remove_model_indexes(
167+
field.embedded_model, parent_model=model, column_prefix=new_path
168+
)
169+
170+
def _remove_model_indexes(self, model, column_prefix="", parent_model=None):
171+
"""
172+
When removing an EmbeddedModelField, the indexes need to be removed
173+
recursively.
174+
"""
175+
if not model._meta.managed or model._meta.proxy or model._meta.swapped:
176+
return
177+
# Field indexes and uniques
178+
for field in model._meta.local_fields:
179+
if isinstance(field, EmbeddedModelField):
180+
new_path = f"{column_prefix}{field.column}."
181+
self._remove_model_indexes(
182+
field.embedded_model, parent_model=parent_model or model, column_prefix=new_path
183+
)
184+
if self._field_should_be_indexed(model, field):
185+
self._remove_field_index(parent_model or model, field, column_prefix=column_prefix)
186+
elif self._field_should_have_unique(field):
187+
self._remove_field_unique(parent_model or model, field, column_prefix=column_prefix)
188+
# Meta.index_together (RemovedInDjango51Warning)
189+
for field_names in model._meta.index_together:
190+
self._remove_composed_index(
191+
model,
192+
field_names,
193+
{"index": True, "unique": False},
194+
column_prefix=column_prefix,
195+
parent_model=parent_model,
196+
)
197+
# Meta.unique_together
198+
if model._meta.unique_together:
199+
self.alter_unique_together(
200+
model,
201+
model._meta.unique_together,
202+
[],
203+
column_prefix=column_prefix,
204+
parent_model=parent_model,
205+
)
206+
# Meta.constraints
207+
for constraint in model._meta.constraints:
208+
self.remove_constraint(
209+
model, constraint, column_prefix=column_prefix, parent_model=parent_model
210+
)
211+
# Meta.indexes
212+
for index in model._meta.indexes:
213+
self.remove_index(model, index, column_prefix=column_prefix, parent_model=parent_model)
165214

166215
def alter_index_together(self, model, old_index_together, new_index_together, column_prefix=""):
167216
olds = {tuple(fields) for fields in old_index_together}
168217
news = {tuple(fields) for fields in new_index_together}
169218
# Deleted indexes
170219
for field_names in olds.difference(news):
171-
self._remove_composed_index(model, field_names, {"index": True, "unique": False})
220+
self._remove_composed_index(
221+
model, field_names, {"index": True, "unique": False}, column_prefix=""
222+
)
172223
# Created indexes
173224
for field_names in news.difference(olds):
174225
self._add_composed_index(model, field_names, column_prefix=column_prefix)
@@ -256,16 +307,18 @@ def remove_index(self, model, index):
256307
return
257308
self.get_collection(model._meta.db_table).drop_index(index.name)
258309

259-
def _remove_composed_index(self, model, field_names, constraint_kwargs):
310+
def _remove_composed_index(
311+
self, model, field_names, constraint_kwargs, column_prefix="", parent_model=None
312+
):
260313
"""
261314
Remove the index on the given list of field_names created by
262315
index/unique_together, depending on constraint_kwargs.
263316
"""
264317
meta_constraint_names = {constraint.name for constraint in model._meta.constraints}
265318
meta_index_names = {constraint.name for constraint in model._meta.indexes}
266-
columns = [model._meta.get_field(field).column for field in field_names]
319+
columns = [column_prefix + model._meta.get_field(field).column for field in field_names]
267320
constraint_names = self._constraint_names(
268-
model,
321+
parent_model or model,
269322
columns,
270323
exclude=meta_constraint_names | meta_index_names,
271324
**constraint_kwargs,
@@ -277,16 +330,17 @@ def _remove_composed_index(self, model, field_names, constraint_kwargs):
277330
f"Found wrong number ({num_found}) of constraints for "
278331
f"{model._meta.db_table}({columns_str})."
279332
)
333+
model = parent_model or model
280334
collection = self.get_collection(model._meta.db_table)
281335
collection.drop_index(constraint_names[0])
282336

283-
def _remove_field_index(self, model, field):
337+
def _remove_field_index(self, model, field, column_prefix=""):
284338
"""Remove a field's db_index=True index."""
285339
collection = self.get_collection(model._meta.db_table)
286340
meta_index_names = {index.name for index in model._meta.indexes}
287341
index_names = self._constraint_names(
288342
model,
289-
[field.column],
343+
[column_prefix + field.column],
290344
index=True,
291345
# Retrieve only BTREE indexes since this is what's created with
292346
# db_index=True.
@@ -345,12 +399,12 @@ def remove_constraint(self, model, constraint):
345399
)
346400
self.remove_index(model, idx)
347401

348-
def _remove_field_unique(self, model, field):
402+
def _remove_field_unique(self, model, field, column_prefix=""):
349403
# Find the unique constraint for this field
350404
meta_constraint_names = {constraint.name for constraint in model._meta.constraints}
351405
constraint_names = self._constraint_names(
352406
model,
353-
[field.column],
407+
[column_prefix + field.column],
354408
unique=True,
355409
primary_key=False,
356410
exclude=meta_constraint_names,

tests/schema_/test_embedded_model.py

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,9 +392,128 @@ class Meta:
392392
editor.delete_model(Author)
393393
self.assertTableNotExists(Author)
394394

395-
# SchemaEditor.add_field() tests
395+
# SchemaEditor.add_field() / remove_field() tests
396396
@isolate_apps("schema_")
397-
def test_add_field_db_index(self):
397+
def test_add_remove_field_db_index_and_unique(self):
398+
"""AddField + EmbeddedModelField"""
399+
400+
class Book(models.Model):
401+
name = models.CharField(max_length=100)
402+
403+
class Meta:
404+
app_label = "schema_"
405+
406+
new_field = EmbeddedModelField(Author)
407+
new_field.set_attributes_from_name("author")
408+
with connection.schema_editor() as editor:
409+
# Create the table amd add the field.
410+
editor.create_model(Book)
411+
editor.add_field(Book, new_field)
412+
# Embedded indexes are created.
413+
self.assertEqual(
414+
self.get_constraints_for_columns(Book, ["author.age"]),
415+
["schema__book_author.age_dc08100b"],
416+
)
417+
self.assertEqual(
418+
self.get_constraints_for_columns(Book, ["author.address.zip_code"]),
419+
["schema__book_author.address.zip_code_7b9a9307"],
420+
)
421+
# Embedded uniques
422+
self.assertEqual(
423+
self.get_constraints_for_columns(Book, ["author.employee_id"]),
424+
["schema__book_author.employee_id_7d4d3eff_uniq"],
425+
)
426+
self.assertEqual(
427+
self.get_constraints_for_columns(Book, ["author.address.uid"]),
428+
["schema__book_author.address.uid_8124a01f_uniq"],
429+
)
430+
editor.remove_field(Book, new_field)
431+
# Embedded indexes are removed.
432+
self.assertEqual(
433+
self.get_constraints_for_columns(Book, ["author.age"]),
434+
[],
435+
)
436+
self.assertEqual(
437+
self.get_constraints_for_columns(Book, ["author.address.zip_code"]),
438+
[],
439+
)
440+
self.assertEqual(
441+
self.get_constraints_for_columns(Book, ["author.employee_id"]),
442+
[],
443+
)
444+
self.assertEqual(
445+
self.get_constraints_for_columns(Book, ["author.address.uid"]),
446+
[],
447+
)
448+
editor.delete_model(Book)
449+
self.assertTableNotExists(Author)
450+
451+
@ignore_warnings(category=RemovedInDjango51Warning)
452+
@isolate_apps("schema_")
453+
def test_add_remove_field_index_together(self):
454+
"""Meta.index_together on an embedded model."""
455+
456+
class Address(models.Model):
457+
index_together_one = models.CharField(max_length=10)
458+
index_together_two = models.CharField(max_length=10)
459+
460+
class Meta:
461+
app_label = "schema_"
462+
index_together = [("index_together_one", "index_together_two")]
463+
464+
class Author(models.Model):
465+
address = EmbeddedModelField(Address)
466+
index_together_three = models.CharField(max_length=10)
467+
index_together_four = models.CharField(max_length=10)
468+
469+
class Meta:
470+
app_label = "schema_"
471+
index_together = [("index_together_three", "index_together_four")]
472+
473+
class Book(models.Model):
474+
class Meta:
475+
app_label = "schema_"
476+
477+
new_field = EmbeddedModelField(Author)
478+
new_field.set_attributes_from_name("author")
479+
with connection.schema_editor() as editor:
480+
# Create the table amd add the field.
481+
editor.create_model(Book)
482+
editor.add_field(Book, new_field)
483+
# Embedded index_togethers are created.
484+
self.assertEqual(
485+
self.get_constraints_for_columns(
486+
Book, ["author.address.index_together_one", "author.address.index_together_two"]
487+
),
488+
["schema__add_index_t_efa93e_idx"],
489+
)
490+
self.assertEqual(
491+
self.get_constraints_for_columns(
492+
Book,
493+
["author.index_together_three", "author.index_together_four"],
494+
),
495+
["schema__aut_index_t_df32aa_idx"],
496+
)
497+
editor.remove_field(Book, new_field)
498+
# Embedded indexes are removed.
499+
self.assertEqual(
500+
self.get_constraints_for_columns(
501+
Book, ["author.address.index_together_one", "author.address.index_together_two"]
502+
),
503+
[],
504+
)
505+
self.assertEqual(
506+
self.get_constraints_for_columns(
507+
Book,
508+
["author.index_together_three", "author.index_together_four"],
509+
),
510+
[],
511+
)
512+
editor.delete_model(Book)
513+
self.assertTableNotExists(Book)
514+
515+
@isolate_apps("schema_")
516+
def _test_add_field_db_index(self):
398517
"""AddField + EmbeddedModelField"""
399518

400519
class Book(models.Model):
@@ -419,5 +538,15 @@ class Meta:
419538
self.get_constraints_for_columns(Book, ["author.address.zip_code"]),
420539
["schema__book_author.address.zip_code_7b9a9307"],
421540
)
541+
editor.remove_field(Book, new_field)
542+
# Embedded indexes are removed.
543+
self.assertEqual(
544+
self.get_constraints_for_columns(Book, ["author.age"]),
545+
[],
546+
)
547+
self.assertEqual(
548+
self.get_constraints_for_columns(Book, ["author.address.zip_code"]),
549+
[],
550+
)
422551
editor.delete_model(Book)
423552
self.assertTableNotExists(Author)

0 commit comments

Comments
 (0)