#22777 closed Bug (fixed)
Foreignkey does (sometimes) not get added to migration of M2M with a through model
Reported by: | Vidir Valberg Gudmundsson | Owned by: | nobody |
---|---|---|---|
Component: | Migrations | Version: | dev |
Severity: | Release blocker | Keywords: | |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
The following models:
from django.conf import settings from django.db import models class Event(models.Model): participants = models.ManyToManyField( settings.AUTH_USER_MODEL, through='testapp.Participant', related_name='events' ) class Participant(models.Model): event = models.ForeignKey( 'testapp.Event', related_name='associations', ) user = models.ForeignKey( settings.AUTH_USER_MODEL )
Result in the following migration
$ ./manage.py makemigrations Migrations for 'testapp': 0001_initial.py: - Create model Event - Create model Participant $ cat testapp/migrations/0001_initial.py # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models, migrations from django.conf import settings class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( name='Event', fields=[ ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')), ('participants', models.ManyToManyField(through='testapp.Participant', to=settings.AUTH_USER_MODEL)), ], options={ }, bases=(models.Model,), ), migrations.CreateModel( name='Participant', fields=[ ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')), ('event', models.ForeignKey(to_field='id', to='testapp.Event')), ('user', models.ForeignKey(to_field='id', to=settings.AUTH_USER_MODEL)), ], options={ }, bases=(models.Model,), ), ]
When migrating the following error occurs:
$ ./manage.py migrate Operations to perform: Synchronize unmigrated apps: sessions, auth, admin, contenttypes Apply all migrations: testapp 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 testapp.0001_initial...Traceback (most recent call last): File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/apps/config.py", line 152, in get_model return self.models[model_name.lower()] KeyError: 'participant' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/db/migrations/state.py", line 76, in render model = self.apps.get_model(lookup_model[0], lookup_model[1]) File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/apps/registry.py", line 190, in get_model return self.get_app_config(app_label).get_model(model_name.lower()) File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/apps/config.py", line 155, in get_model "App '%s' doesn't have a '%s' model." % (self.label, model_name)) LookupError: App 'testapp' doesn't have a 'participant' model. During handling of the above exception, another exception occurred: Traceback (most recent call last): File "./manage.py", line 10, in <module> execute_from_command_line(sys.argv) File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/core/management/__init__.py", line 385, in execute_from_command_line utility.execute() File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/core/management/__init__.py", line 377, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/core/management/base.py", line 288, in run_from_argv self.execute(*args, **options.__dict__) File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/core/management/base.py", line 337, in execute output = self.handle(*args, **options) File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/core/management/commands/migrate.py", line 146, in handle executor.migrate(targets, plan, fake=options.get("fake", False)) File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/db/migrations/executor.py", line 62, in migrate self.apply_migration(migration, fake=fake) File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/db/migrations/executor.py", line 96, in apply_migration migration.apply(project_state, schema_editor) File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/db/migrations/migration.py", line 107, in apply operation.database_forwards(self.app_label, schema_editor, project_state, new_state) File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/db/migrations/operations/models.py", line 33, in database_forwards apps = to_state.render() File "/home/valberg/.virtualenvs/django/lib/python3.3/site-packages/django/db/migrations/state.py", line 86, in render model=lookup_model, ValueError: Lookup failed for model referenced by field testapp.Event.participants: testapp.Participant
The odd thing is that the following models (same structure as above, just different names):
from django.conf import settings from django.db import models # Same as Event above class Foo(models.Model): users = models.ManyToManyField( settings.AUTH_USER_MODEL, through='testapp.Bar', related_name='foos' ) # Same as Participant above class Bar(models.Model): foo = models.ForeignKey( 'testapp.Foo', related_name='bars', ) user = models.ForeignKey( settings.AUTH_USER_MODEL )
Result in the following:
$ ./manage.py makemigrations Migrations for 'testapp': 0001_initial.py: - Create model Bar - Create model Foo - Add field foo to bar $ cat testapp/migrations/0001_initial.py # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models, migrations from django.conf import settings class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( name='Bar', fields=[ ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), ('user', models.ForeignKey(to_field='id', to=settings.AUTH_USER_MODEL)), ], options={ }, bases=(models.Model,), ), migrations.CreateModel( name='Foo', fields=[ ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), ('users', models.ManyToManyField(to=settings.AUTH_USER_MODEL, through='testapp.Bar')), ], options={ }, bases=(models.Model,), ), migrations.AddField( model_name='bar', name='foo', field=models.ForeignKey(to_field='id', to='testapp.Foo'), preserve_default=True, ), ] $ ./manage.py migrate Operations to perform: Synchronize unmigrated apps: admin, auth, sessions, contenttypes Apply all migrations: testapp 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 testapp.0001_initial... OK
So somehow the naming of the models has a say in how the migrations are made. In the failing example there is no creation of the FK from Participant to Event as there is from Bar to Foo.
Change History (4)
comment:1 by , 11 years ago
Severity: | Normal → Release blocker |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 11 years ago
Looks like there's not enough dependency stuff set in the autodetector to force the operation ordering. Hopefully an easy-ish fix.
comment:3 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Hi,
I can reproduce your issue with this simplified models (no reference to
settings.AUTH_USER_MODEL
):As you mentionned, renaming
FooBar
toAFooBar
(so that it appears before when sorting alphabetically) makes everything work.I'll upgrade the ticket to a release blocker.
Thanks.