Opened 39 minutes ago
Last modified 39 minutes ago
#37477 new Bug
makemigrations orders AlterModelOptions before RenameModel when a new model has an FK to the renamed model
| Reported by: | Akshat Gupta | Owned by: | |
|---|---|---|---|
| Component: | Migrations | Version: | dev |
| Severity: | Normal | Keywords: | autodetector, RenameModel |
| Cc: | Akshat Gupta | Triage Stage: | Unreviewed |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
When a model is renamed, `makemigrations` can put operations on the new model name before the `RenameModel` operation. `migrate` then crashes with a `KeyError`. It needs three things in one `makemigrations` run: 1. A model is renamed (and the rename prompt is answered "y"). 2. Its Meta options change, for example `ordering`. 3. A new model with a ForeignKey to the renamed model is added. Starting point (migrated):
class Author(models.Model): name = models.CharField(max_length=50)
Changed to:
class Writer(models.Model): name = models.CharField(max_length=50) class Meta: ordering = ["name"] class Book(models.Model): title = models.CharField(max_length=50) writer = models.ForeignKey(Writer, on_delete=models.CASCADE)
`makemigrations` ("Was the model shop.Author renamed to Writer? y") writes the operations in this order:
operations = [ migrations.AlterModelOptions(name="writer", options={"ordering": ["name"]}), migrations.RenameModel(old_name="Author", new_name="Writer"), migrations.CreateModel(name="Book", ...), ]
`migrate` fails:
File ".../django/db/migrations/state.py", line 183, in alter_model_options
model_state = self.models[app_label, model_name]
KeyError: ('shop', 'writer')
Without the new `Book` model the order is correct. I also see `AddIndex` and `AddConstraint` on the renamed model emitted before `RenameModel` in the same situation.
Cause: `generate_renamed_models()` gives `RenameModel` dependencies for the reverse relations of the renamed model. A new model with an FK to it makes `RenameModel` depend on that `CreateModel`. The options, index and constraint operations on the renamed model have no dependency on `RenameModel`. `_sort_migrations()` emits operations without dependencies first, so they end up before the rename.
A fix could make every operation on a renamed model depend on its `RenameModel` in `_sort_migrations()`. I tried this locally and the migrations tests pass.
Tested on main (6.2 dev) with SQLite.
Note:
See TracTickets
for help on using tickets.