Opened 8 years ago

Closed 8 years ago

Last modified 8 years ago

#22965 closed Bug (duplicate)

InvalidBasesError for unmigrated apps subclassing contrib

Reported by: Collin Anderson Owned by: nobody
Component: Migrations Version: 1.7-rc-1
Severity: Release blocker Keywords:
Cc: cmawebsite@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Unmigrated app in a project not swapping out the User model:

from django.contrib.auth.models import User
from django.db import models


class UserProfile(User):
    bio = models.TextField()

syncdb and migrate give this error on latest 1.7 and master:

~/usersubclasstest$ rm db.sqlite3; PYTHONPATH=../django1.7 ./manage.py syncdb
Operations to perform:
  Synchronize unmigrated apps: account
  Apply all migrations: admin, contenttypes, auth, sessions
Synchronizing apps without migrations:
  Creating tables...
    Creating table account_userprofile
  Installing custom SQL...
  Installing indexes...
Running migrations:
  Applying contenttypes.0001_initial...Traceback (most recent call last):
  File "./manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/collin/django1.7/django/core/management/__init__.py", line 385, in execute_from_command_line
    utility.execute()
  File "/home/collin/django1.7/django/core/management/__init__.py", line 377, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/collin/django1.7/django/core/management/base.py", line 288, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/home/collin/django1.7/django/core/management/base.py", line 337, in execute
    output = self.handle(*args, **options)
  File "/home/collin/django1.7/django/core/management/base.py", line 532, in handle
    return self.handle_noargs(**options)
  File "/home/collin/django1.7/django/core/management/commands/syncdb.py", line 27, in handle_noargs
    call_command("migrate", **options)
  File "/home/collin/django1.7/django/core/management/__init__.py", line 115, in call_command
    return klass.execute(*args, **defaults)
  File "/home/collin/django1.7/django/core/management/base.py", line 337, in execute
    output = self.handle(*args, **options)
  File "/home/collin/django1.7/django/core/management/commands/migrate.py", line 160, in handle
    executor.migrate(targets, plan, fake=options.get("fake", False))
  File "/home/collin/django1.7/django/db/migrations/executor.py", line 62, in migrate
    self.apply_migration(migration, fake=fake)
  File "/home/collin/django1.7/django/db/migrations/executor.py", line 90, in apply_migration
    if self.detect_soft_applied(migration):
  File "/home/collin/django1.7/django/db/migrations/executor.py", line 134, in detect_soft_applied
    apps = project_state.render()
  File "/home/collin/django1.7/django/db/migrations/state.py", line 71, in render
    raise InvalidBasesError("Cannot resolve bases for %r" % new_unrendered_models)
django.db.migrations.state.InvalidBasesError: Cannot resolve bases for [<ModelState: 'account.UserProfile'>]

Initializing the database using 1.6 syncdb doesn't help either (unless you use --fake).

I have a minimal project that reproduces the error on github.

Feel free to remove the release blocker status if what I'm doing isn't supported. If it's not supported, we should have a more helpful error message.

Change History (8)

comment:1 Changed 8 years ago by Collin Anderson

Severity: Release blockerNormal
Summary: migrations break subclasses of Userbetter error message for unmigrated apps depending on migrated apps.

Ahh, sure enough the release notes say "It is not advised to have apps without migrations depend on ... apps with migrations."

Seems to me we should say something stronger than "It is not advised". Maybe we should list it under "Backwards incompatible changes"? Maybe we should add a check or a better error message?

comment:2 Changed 8 years ago by Collin Anderson

Severity: NormalRelease blocker
Summary: better error message for unmigrated apps depending on migrated apps.InvalidBasesError for unmigrated apps subclassing contrib

Marking as release blocker because someone else ran into it. https://code.djangoproject.com/ticket/22708#comment:16

comment:3 Changed 8 years ago by Collin Anderson

The issue is that non migrated apps are synced before migrations happen. Could we detect the dependency and run just those migrations first? Or syncdb any depended base models and then fake their initial migrations later.

comment:4 Changed 8 years ago by Collin Anderson

Or, I'm a little naive here, wouldn't it be saner to migrate first and syncdb second? It would mean you can't use migrations until your dependencies use migrations which seems fine to me (though could be a problem for non-migrated custom user models).

comment:5 Changed 8 years ago by Tim Graham

Triage Stage: UnreviewedAccepted

The same issue was also reported in #22922. I changed the summary there to "Add a better error message or an FAQ entry for InvalidBasesError" so if there's no code changes we can make here, this would be a duplicate of that.

Last edited 8 years ago by Tim Graham (previous) (diff)

comment:6 Changed 8 years ago by Andrew Godwin

Resolution: duplicate
Status: newclosed

Yep, closing this in favour of #22922; this error is probably most caused by unmigrated depending on migrated.

Collin: If we had migrated run before syncdb, then migrated apps couldn't depend on unmigrated apps, which is much more untenable (think about all the unmigrated apps in the wild; most new apps are going to be migrated, so this way round works best). To detect dependencies we'd need to give them migrations (due to the way syncdb handles circular foreign keys) and tada, the problem has gone away anyway.

I wish we could solve this problem but I've looked into it a lot and we can't. The reason the language is "it's not advised" is because you can depend with foreign keys and suchlike fine; it's importing a base class that really blows stuff up. We should at least mention that by name, and probably call out auth specifically in the release notes as it's now migrated.

comment:7 Changed 8 years ago by Collin Anderson

That makes sense. Thanks so much.

comment:8 Changed 8 years ago by Collin Anderson

If it helps anyone else, I'll note that I've avoided creating migrations for my app by creating a "fake" custom user model in my app:

in myapp/models.py:

from django.contrib.auth.models import AbstractUser


class User(AbstractUser):

    class Meta:
        db_table = 'auth_user'

and in settings.py

AUTH_USER_MODEL = 'myapp.User'
Note: See TracTickets for help on using tickets.
Back to Top