#23630 closed Bug (fixed)
AlterModelTable doesn't rename auto-created tables
Reported by: | no | Owned by: | Tim Graham |
---|---|---|---|
Component: | Migrations | Version: | 1.7 |
Severity: | Release blocker | Keywords: | |
Cc: | github@…, Shai Berger | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
According to https://docs.djangoproject.com/en/dev/ref/models/fields/#ref-manytomany, when a m2m field uses an automatic (implicit) through model, the through model's table is named by combining the containing model's table-name and the field name. Consequently, if a model contains such m2m fields and its table name is changed by a migration, the m2m field's tables should also be renamed.
This doesn't happen (see comment:4 and comment:5 for details), leading to broken models.
Change History (13)
comment:1 by , 10 years ago
Triage Stage: | Unreviewed → Accepted |
---|
follow-up: 3 comment:2 by , 10 years ago
Cc: | added |
---|
comment:1 : The error seems to be about table asdf
, the named table of the model. Are you sure you ran the migration?
Also, according to https://docs.djangoproject.com/en/dev/ref/models/fields/#ref-manytomany changing the table name for model Foo should not change anything; the M2M table should still be named app_bar_foos
. A change should happen if the Bar
table name is modified.
comment:3 by , 10 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
Replying to shaib:
Are you sure you ran the migration?
Ugh, not sure what I did there but I can't seem to be able to reproduce it now so probably you're right.
I also don't see any reason to rename the M2M table, so I'm marking this as wontfix
.
Feel free to reopen this ticket if you have some more arguments for this feature, or you can also raise the issue on the django-developers mailing list.
Thanks.
comment:4 by , 10 years ago
Resolution: | wontfix |
---|---|
Status: | closed → new |
Steps to reproduce:
- Create models as such:
class Spam(models.Model): class Meta: db_table = 'hello_spam' class Eggs(models.Model): class Meta: db_table = 'hello_eggs' m2m = models.ManyToManyField(Spam)
- Create, and run, a migration. Tables created:
$ sqlite3 db.sqlite3 .tables django_migrations hello_eggs hello_eggs_m2m hello_spam
- Remove the
Meta.db_table
entries. - Create an empty migration.
- Add the following to the migration (this step should be automated, but is blocked on #23629):
class Migration(migrations.Migration): dependencies = [ ('spam', '0001_initial'), ] operations = [ # Rename the models to what they should default to migrations.AlterModelTable( name = 'Spam', table = 'spam_spam' ), migrations.AlterModelTable( name = 'Eggs', table = 'spam_eggs' ), ]
- Run migrations. Current tables:
$ sqlite3 db.sqlite3 .tables django_migrations hello_eggs_m2m spam_eggs spam_spam
As you can see, the m2m table isn't renamed, and one would have to manually add the following to the migration:
migrations.RunPython(lambda a, e: e.alter_db_table(None, 'hello_eggs_m2m', 'spam_eggs_m2m'))
comment:5 by , 10 years ago
Description: | modified (diff) |
---|---|
Severity: | Normal → Release blocker |
I've been able to reproduce the problem as described in comment:4. I've also verified that this is independent of whether the (main) models use the default table name -- the behavior is the same when changing from non-default to default (as in comment:4), from default to non-default, or between two different non-default names.
Marking as a release blocker as well -- this is, IMO, as important as #23629.
comment:6 by , 10 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:7 by , 10 years ago
Cc: | added |
---|
My thinking is to add a check in the generate_altered_db_table() method and add an AlterModelTable
operation for the implicit M2M model to fix this, but m2m_field.rel.through
is returning None
there instead of behaving the way it does in a normal shell: Eggs._meta.get_field('m2m').rel.through._meta.db_table
-> 'hello_eggs_m2m'
. Andrew, do you have any guidance?
comment:8 by , 10 years ago
tim: During autodetection, the relations occasionally don't have rel.through populated and I'm not sure why that's the case. There's a couple of checks elsewhere for this same behaviour, but I think before it was just ForeignKeys having an unused through or something (it's been long enough that I can't remember).
Technically, the rename should be done by AlterModelTable rather than by the autogenerator making extra stanzas of changes (in the same way that RenameField also modifies FKs that point to it), but I don't mind this solution either if it works well.
comment:9 by , 10 years ago
Has patch: | set |
---|---|
Patch needs improvement: | set |
Thanks, Andrew. I made a PR based on your advice, although there's one thing there I'm not quite sure about (noted with a "hack" comment). If you could take a look and advise I'd appreciate it.
comment:11 by , 10 years ago
Patch needs improvement: | unset |
---|
comment:12 by , 10 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
Hi,
Indeed, I can reproduce this issue like so:
Create an app with the following models:
Run
makemigrations
to create the initial migration then change theFoo
model to:Since the
db_table
change isn't auto-detected (#23629), also create a migration (makemigrations --empty appname
):After that, run
migrate
to sync the database.Once that's done, running
Foo.objects.create()
triggers the following error:Ideally, the
AlterModelTable
operation should be smart enough rename the M2M and foreignkeys pointing to the model whose table has changed.If that's not possible, the limitation should definitely be documented.
Thanks.