#22476 closed Bug (fixed)
Migrations fail to migrate m2m fields with custom through model.
| Reported by: | Florian Apolloner | Owned by: | Andrew Godwin |
|---|---|---|---|
| Component: | Migrations | Version: | dev |
| Severity: | Release blocker | Keywords: | migrations, m2m |
| Cc: | Andrew Godwin, Florian Apolloner, k@… | Triage Stage: | Accepted |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Changing blank and other attributes on a m2m field fails, models:
from django.db import models
class Table1(models.Model):
pass
class Table2(models.Model):
m2m = models.ManyToManyField(Table1, through='M2M')
class M2M(models.Model):
t1 = models.ForeignKey(Table1, related_name='+')
t2 = models.ForeignKey(Table2, related_name='+')
Reproduce by running makemigrations, changing blank to True on the m2m field, rerunning makemigrations and migrate, resulting in:
Operations to perform:
Synchronize unmigrated apps: admin, contenttypes, auth, sessions
Apply all migrations: t1
Synchronizing apps without migrations:
Creating tables...
Creating table django_admin_log
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session
Installing custom SQL...
Installing indexes...
Running migrations:
Applying t1.0001_initial... OK
Applying t1.0002_m2m_t2... OK
Applying t1.0003_auto_20140419_1201...Traceback (most recent call last):
File "./manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/home/florian/sources/django.git/django/core/management/__init__.py", line 427, in execute_from_command_line
utility.execute()
File "/home/florian/sources/django.git/django/core/management/__init__.py", line 419, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/florian/sources/django.git/django/core/management/base.py", line 288, in run_from_argv
self.execute(*args, **options.__dict__)
File "/home/florian/sources/django.git/django/core/management/base.py", line 337, in execute
output = self.handle(*args, **options)
File "/home/florian/sources/django.git/django/core/management/commands/migrate.py", line 145, in handle
executor.migrate(targets, plan, fake=options.get("fake", False))
File "/home/florian/sources/django.git/django/db/migrations/executor.py", line 60, in migrate
self.apply_migration(migration, fake=fake)
File "/home/florian/sources/django.git/django/db/migrations/executor.py", line 94, in apply_migration
migration.apply(project_state, schema_editor)
File "/home/florian/sources/django.git/django/db/migrations/migration.py", line 97, in apply
operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
File "/home/florian/sources/django.git/django/db/migrations/operations/fields.py", line 130, in database_forwards
schema_editor.alter_field(from_model, from_field, to_field)
File "/home/florian/sources/django.git/django/db/backends/sqlite3/schema.py", line 151, in alter_field
new_field,
ValueError: Cannot alter field t1.Table2.m2m into t1.Table2.m2m - they are not compatible types (probably means only one is an M2M with implicit through model)
Marking as release blocker since this is a bug in a new feature
Change History (10)
comment:1 by , 12 years ago
| Cc: | added |
|---|
comment:2 by , 12 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|
comment:3 by , 11 years ago
comment:4 by , 11 years ago
| Cc: | added |
|---|
I can reproduce this, and the M2M uses a through model both before and after. The only difference is the addition of blank=True. My understanding was that blank is used for form validation and doesn't affect the database at all. Am I missing something?
comment:5 by , 11 years ago
Hm, that should be allowable - you're getting the exact same traceback as in the ticket description?
comment:6 by , 11 years ago
Yes, it is exactly the same traceback (other than the model / field names, since I'm seeing this on an actual project). This is after making the lone blank=True change, and getting this single operation in the migrations file generated by makemigrations:
operations = [
migrations.AlterField(
model_name='question',
name='tags',
field=models.ManyToManyField(to=u'questions.Tag', through=u'questions.ContentTag', blank=True),
),
]
comment:7 by , 11 years ago
Alright, I'll make sure I cover that too; I suspect there's an easy fix where I can just ignore if the to and through properties match.
comment:8 by , 11 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:9 by , 11 years ago
| Resolution: | → fixed |
|---|---|
| Status: | assigned → closed |
I say this is valid behaviour - as the error message says, you cannot alter an M2M without a through model into one with a through model, at least not in the current system.
I propose the only change we make is that the autodetector raises the error when creating the migrations rather than it happening at runtime, and suggests that you can remove and add the field instead if you really want to drop all data and change it.