#22783 closed Bug (fixed)
Auto-created migrations place custom user model *after* things that depend on it.
Reported by: | Stephen Burrows | Owned by: | Andrew Godwin |
---|---|---|---|
Component: | Migrations | Version: | 1.7-beta-2 |
Severity: | Release blocker | Keywords: | |
Cc: | Stephen Burrows | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Ran into this when I tried to pull the latest stable/1.7.x (currently @ c8c1883962ebb0668663134e023ffbe1c753a450) and re-generate migrations for django-brambling (@ d479f0666c7fe4d5d9f11554737909dc8504ce43).
The error I'm getting is:
ValueError: Lookup failed for model referenced by field brambling.Attendee.event_person: brambling.EventPerson
The reason I'm getting this error AFAICT is that brambling.Person
is a swappable user model, and is being placed *after* things that depend on it.
I had to revert to 52b7e772e4da846efb2d75b22ec05c7105091b76 to get things working.
Change History (8)
comment:1 by , 10 years ago
comment:2 by , 10 years ago
Triage Stage: | Unreviewed → Accepted |
---|
I can confirm this in master (after applying patch from #22848 that is).
from django.db import models from django.contrib.auth.models import AbstractUser from django.conf import settings class Article(models.Model): body = models.TextField() user = models.ForeignKey(settings.AUTH_USER_MODEL) class Profile(AbstractUser): about = models.TextField()
Results in this migration:
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models, migrations import django.utils.timezone import django.core.validators from django.conf import settings class Migration(migrations.Migration): dependencies = [ ('auth', '__latest__'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( name='Article', fields=[ ('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)), ('body', models.TextField()), ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, to_field='id')), ], options={ }, bases=(models.Model,), ), migrations.CreateModel( name='Profile', fields=[ ('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)), ('password', models.CharField(verbose_name='password', max_length=128)), ('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login')), ('is_superuser', models.BooleanField(default=False, verbose_name='superuser status', help_text='Designates that this user has all permissions without explicitly assigning them.')), ('username', models.CharField(unique=True, verbose_name='username', max_length=30, help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username.', 'invalid')])), ('first_name', models.CharField(verbose_name='first name', blank=True, max_length=30)), ('last_name', models.CharField(verbose_name='last name', blank=True, max_length=30)), ('email', models.EmailField(verbose_name='email address', blank=True, max_length=75)), ('is_staff', models.BooleanField(default=False, verbose_name='staff status', help_text='Designates whether the user can log into this admin site.')), ('is_active', models.BooleanField(default=True, verbose_name='active', help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.')), ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), ('about', models.TextField()), ('groups', models.ManyToManyField(verbose_name='groups', blank=True, to='auth.Group')), ('user_permissions', models.ManyToManyField(verbose_name='user permissions', blank=True, to='auth.Permission')), ], options={ 'verbose_name': 'user', 'abstract': False, 'verbose_name_plural': 'users', }, bases=(models.Model,), ), ]
and this error when trying to migrate:
$ ./manage.py migrate Operations to perform: Synchronize unmigrated apps: auth, contenttypes, sessions Apply all migrations: testapp, admin Synchronizing apps without migrations: Creating tables... Installing custom SQL... Installing indexes... Running migrations: Applying testapp.0001_initial...Traceback (most recent call last): File "/Users/valberg/Code/forks/django/django/apps/config.py", line 152, in get_model return self.models[model_name.lower()] KeyError: 'profile' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/Users/valberg/Code/forks/django/django/db/migrations/state.py", line 79, in render model = self.apps.get_model(lookup_model[0], lookup_model[1]) File "/Users/valberg/Code/forks/django/django/apps/registry.py", line 190, in get_model return self.get_app_config(app_label).get_model(model_name.lower()) File "/Users/valberg/Code/forks/django/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 'profile' 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 "/Users/valberg/Code/forks/django/django/core/management/__init__.py", line 385, in execute_from_command_line utility.execute() File "/Users/valberg/Code/forks/django/django/core/management/__init__.py", line 377, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/Users/valberg/Code/forks/django/django/core/management/base.py", line 288, in run_from_argv self.execute(*args, **options.__dict__) File "/Users/valberg/Code/forks/django/django/core/management/base.py", line 337, in execute output = self.handle(*args, **options) File "/Users/valberg/Code/forks/django/django/core/management/commands/migrate.py", line 146, in handle executor.migrate(targets, plan, fake=options.get("fake", False)) File "/Users/valberg/Code/forks/django/django/db/migrations/executor.py", line 62, in migrate self.apply_migration(migration, fake=fake) File "/Users/valberg/Code/forks/django/django/db/migrations/executor.py", line 96, in apply_migration migration.apply(project_state, schema_editor) File "/Users/valberg/Code/forks/django/django/db/migrations/migration.py", line 107, in apply operation.database_forwards(self.app_label, schema_editor, project_state, new_state) File "/Users/valberg/Code/forks/django/django/db/migrations/operations/models.py", line 33, in database_forwards apps = to_state.render() File "/Users/valberg/Code/forks/django/django/db/migrations/state.py", line 89, in render model=lookup_model, ValueError: Lookup failed for model referenced by field testapp.Article.user: testapp.Profile
comment:3 by , 10 years ago
Severity: | Normal → Release blocker |
---|
comment:4 by , 10 years ago
Apparently the order of the operations
list is not the issue. Just tried with these models:
class AProfile(AbstractUser): about = models.TextField() class ZArticle(models.Model): body = models.TextField() user = models.ForeignKey(settings.AUTH_USER_MODEL)
which puts the AProfile
model first in the operations
list in the migration.
comment:5 by , 10 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:6 by , 10 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
comment:8 by , 10 years ago
I tried to replicate with the models the other way around (in operations) and it worked correctly, as I suspected - the ordering is the issue here. The fix will try and order swappable models first on a best-effort basis.
This problem is actually unsolvable in the general case; Django provides no way of telling if a model is a potential candidate for being swapped in in the future, so if you're doing your own swappable settings you may run into this (the fix just deals with AUTH_USER_MODEL
). Manually re-ordering the operations should fix your problem.
The commit you referenced after "I had to revert..." is a doc patch.