class A(models.Model):
createdByUser = models.ForeignKey('User', related_name='creations+',
verbose_name='creatorUser', blank=True, null=True, editable=False,
on_delete=models.PROTECT)
class B(A):
pass
class User(AbstractBaseUser, B):
email = models.EmailField('email address', max_length=256,
unique=True, db_index=True)
USERNAME_FIELD = 'email'
@property
def username(self):
return self.email
}}}
settings.py contains:
{{{
AUTH_USER_MODEL = 'core.User'
}}}
{{{
Applying core.0001_initial...Traceback (most recent call last):
File "./manage.py", line 13, in <module>
execute_from_command_line(sys.argv)
File ".../lib/python3.6/site-
packages/django/core/management/__init__.py", line 364, in
execute_from_command_line
utility.execute()
File ".../lib/python3.6/site-
packages/django/core/management/__init__.py", line 356, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File ".../lib/python3.6/site-packages/django/core/management/base.py",
line 283, in run_from_argv
self.execute(*args, **cmd_options)
File ".../lib/python3.6/site-packages/django/core/management/base.py",
line 330, in execute
output = self.handle(*args, **options)
File ".../lib/python3.6/site-
packages/django/core/management/commands/migrate.py", line 204, in handle
fake_initial=fake_initial,
File ".../lib/python3.6/site-packages/django/db/migrations/executor.py",
line 115, in migrate
state = self._migrate_all_forwards(state, plan, full_plan, fake=fake,
fake_initial=fake_initial)
File ".../lib/python3.6/site-packages/django/db/migrations/executor.py",
line 145, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake,
fake_initial=fake_initial)
File ".../lib/python3.6/site-packages/django/db/migrations/executor.py",
line 244, in apply_migration
state = migration.apply(state, schema_editor)
File ".../lib/python3.6/site-
packages/django/db/migrations/migration.py", line 129, in apply
operation.database_forwards(self.app_label, schema_editor, old_state,
project_state)
File ".../lib/python3.6/site-
packages/django/db/migrations/operations/fields.py", line 88, in
database_forwards
field,
File ".../lib/python3.6/site-
packages/django/db/backends/base/schema.py", line 431, in add_field
definition, params = self.column_sql(model, field,
include_default=True)
File ".../lib/python3.6/site-
packages/django/db/backends/base/schema.py", line 160, in column_sql
db_params = field.db_parameters(connection=self.connection)
File ".../lib/python3.6/site-
packages/django/db/models/fields/related.py", line 994, in db_parameters
return {"type": self.db_type(connection), "check":
self.db_check(connection)}
File ".../lib/python3.6/site-
packages/django/db/models/fields/related.py", line 991, in db_type
return self.target_field.rel_db_type(connection=connection)
File ".../lib/python3.6/site-
packages/django/db/models/fields/related.py", line 909, in target_field
return self.foreign_related_fields[0]
File ".../lib/python3.6/site-
packages/django/db/models/fields/related.py", line 653, in
foreign_related_fields
return tuple(rhs_field for lhs_field, rhs_field in self.related_fields
if rhs_field)
File ".../lib/python3.6/site-
packages/django/db/models/fields/related.py", line 640, in related_fields
self._related_fields = self.resolve_related_fields()
File ".../lib/python3.6/site-
packages/django/db/models/fields/related.py", line 625, in
resolve_related_fields
raise ValueError('Related model %r cannot be resolved' %
self.remote_field.model)
ValueError: Related model 'core.User' cannot be resolved
}}}
Notably, this works fine with any of the following modifications:
- model B is removed, closing the chain
- createdByUser is moved to B or removed altogether
- either A or B is made abstract
- the referenced model is not the custom user model
This is not just a matter of preference for concrete classes, as only a
concrete class can be referenced through a foreign key.
--
Ticket URL: <https://code.djangoproject.com/ticket/29897>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
Comment (by Simon Charette):
Hello there,
Did you reproduce against Django 2.1?
Could you provide the content of your initial migration as well?
--
Ticket URL: <https://code.djangoproject.com/ticket/29897#comment:1>
* severity: Release blocker => Normal
* stage: Unreviewed => Accepted
Comment:
From my local testing this has been broken since at least Django 1.11 but
the `makemigrations`'s behavior changed in the current master as the
optimizer got more aggressive and assumes operation to be appropriately
ordered which is not the case here.
Migrations generated on Django 1.11, 2.0, and 2.1
{{{
Migrations for 'core':
core/migrations/0001_initial.py
- Create model A
- Create model B
- Add field createdByUser to a
- Create model User
}}}
Migration generated on the current master
{{{
Migrations for 'core':
core/migrations/0001_initial.py
- Create model A
- Create model B
- Create model User
}}}
An interesting thing here is that everything works fine on the current
master if `AUTH_USER_MODEL` is not set to `core.User`. Given the optimizer
is completely ''swappable model'' agnostic the issue most probably lies in
the auto-detector ''swappable model'' dependency resolution.
To make it clear the expected operation's order here is the same as if the
model wasn't swappable
{{{
Migrations for 'core':
core/migrations/0001_initial.py
- Create model A
- Create model B
- Create model User
- Add field createdByUser to a
}}}
Downgrading to non-release blocker as this is not a regression and can be
easily worked around by either generating the migration without
`AUTH_USER_MODEL` pointed at `core.User` (and then adjusting it) or by
manually altering the migration to move the `AddField(ForeignKey(User))`
operation after the `CreateModel(User)` one.
--
Ticket URL: <https://code.djangoproject.com/ticket/29897#comment:2>
Old description:
New description:
The following model fails on initial migration.
{{{
from django.db import models
from django.contrib.auth.models import (AbstractBaseUser)
class A(models.Model):
createdByUser = models.ForeignKey('User', related_name='creations+',
verbose_name='creatorUser', blank=True, null=True, editable=False,
on_delete=models.PROTECT)
class B(A):
pass
class User(AbstractBaseUser, B):
email = models.EmailField('email address', max_length=256,
unique=True, db_index=True)
USERNAME_FIELD = 'email'
@property
def username(self):
return self.email
}}}
settings.py contains:
{{{
AUTH_USER_MODEL = 'core.User'
}}}
Output of running the migrations:
--
Comment (by stevenganz):
I accidentally reset your changes to several fields -- please check that
I've restored them appropriately.
This was for an initial migration. Like you, I reproduced it on 1.11 &
2.1.
Your first work-around didn't work for me (perhaps because my actual
models are much more complex), but the second (temporarily updating the
custom user model) does. Thanks, and let me know if you need any more
information.
--
Ticket URL: <https://code.djangoproject.com/ticket/29897#comment:3>
* has_patch: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/29897#comment:4>
Comment (by Simon Charette):
Steven, could you confirm https://github.com/django/django/pull/10577
fixes your issue.
--
Ticket URL: <https://code.djangoproject.com/ticket/29897#comment:5>
Comment (by Steven Ganz):
Yes, that at least gets the migrations to run. Thanks for the quick turn-
around!
--
Ticket URL: <https://code.djangoproject.com/ticket/29897#comment:6>
Comment (by Tim Graham <timograham@…>):
In [changeset:"82353ef940ba661e8c4c1cbc47eb2f62192e4fbe" 82353ef]:
{{{
#!CommitTicketReference repository=""
revision="82353ef940ba661e8c4c1cbc47eb2f62192e4fbe"
Refs #29897 -- Moved autodetector swappable dependency resolution to a
method.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/29897#comment:7>
* status: new => closed
* resolution: => fixed
Comment:
In [changeset:"d8e03fdeb9613b996e52bb5e7f083f7284005600" d8e03fde]:
{{{
#!CommitTicketReference repository=""
revision="d8e03fdeb9613b996e52bb5e7f083f7284005600"
Fixed #29897 -- Fixed autodetector's swappable MTI dependency resolution.
Thanks Steven Ganz for the detailed report.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/29897#comment:8>