* add `test` app with `models.py`:
{{{
class Thing(models.Model):
pass
class SuperThing(Thing):
pass
}}}
* do
{{{
manage.py makemigrations test
}}}
* change `models.py`:
{{{
class SuperThing(models.Model):
thing_ptr = models.AutoField(primary_key=True)
}}}
* do
{{{
manage.py makemigrations test
}}}
* do it one more time
{{{
manage.py makemigrations test
}}}
last command results in
{{{
django.db.migrations.state.InvalidBasesError: Cannot resolve bases for
[<ModelState: 'test.SuperThing'>]
This can happen if you are inheriting models from an app with migrations
(e.g. contrib.auth)
in an app with no migrations; see
https://docs.djangoproject.com/en/1.7/topics/migrations/#dependencies for
more
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/23521>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* needs_docs: => 0
* type: Uncategorized => Bug
* component: Uncategorized => Migrations
* needs_tests: => 0
* needs_better_patch: => 0
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:1>
Comment (by bmispelon):
Hi,
I can't reproduce the issue you're describing.
On master, the second `makemigrations` doesn't detect any changes.
On `stable/1.7.x`, it does create a migration but running it a third time
works (and detects no change as expected).
As a side note, it's not possible to create an app called `test` because
you get this error when doing `manage.py startapp test`:
> CommandError: 'test' conflicts with the name of an existing Python
module and cannot be used as an app name. Please try another name.
Can you provide us with some details on how you're trigerring the issue?
Thanks.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:2>
Comment (by sir-sigurd):
Replying to [comment:2 bmispelon]:
Hi,
Probably this is not obvious, but removal of `Thing` model from
`models.py`, not only from `SuperThing` bases was implied.
[[BR]]
> As a side note, it's not possible to create an app called `test` because
you get this error when doing `manage.py startapp test`
I have never used this for creating apps =)
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:3>
* stage: Unreviewed => Accepted
Comment:
Thanks, that's the bit I was missing.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:4>
* cc: info+coding@… (added)
Old description:
> Steps to reproduce:
>
> * add `test` app with `models.py`:
> {{{
> class Thing(models.Model):
> pass
>
> class SuperThing(Thing):
> pass
> }}}
>
> * do
>
> {{{
> manage.py makemigrations test
> }}}
>
> * change `models.py`:
> {{{
> class SuperThing(models.Model):
> thing_ptr = models.AutoField(primary_key=True)
> }}}
>
> * do
>
> {{{
> manage.py makemigrations test
> }}}
>
> * do it one more time
>
> {{{
> manage.py makemigrations test
> }}}
>
> last command results in
>
> {{{
> django.db.migrations.state.InvalidBasesError: Cannot resolve bases for
> [<ModelState: 'test.SuperThing'>]
> This can happen if you are inheriting models from an app with migrations
> (e.g. contrib.auth)
> in an app with no migrations; see
> https://docs.djangoproject.com/en/1.7/topics/migrations/#dependencies for
> more
> }}}
New description:
Steps to reproduce:
* add `test` app with `models.py`:
{{{
class Thing(models.Model):
pass
class SuperThing(Thing):
pass
}}}
* do
{{{
manage.py makemigrations test
}}}
* change `models.py` (remove `Thing`):
{{{
class SuperThing(models.Model):
thing_ptr = models.AutoField(primary_key=True)
}}}
* do
{{{
manage.py makemigrations test
}}}
* do it one more time
{{{
manage.py makemigrations test
}}}
last command results in
{{{
django.db.migrations.state.InvalidBasesError: Cannot resolve bases for
[<ModelState: 'test.SuperThing'>]
This can happen if you are inheriting models from an app with migrations
(e.g. contrib.auth)
in an app with no migrations; see
https://docs.djangoproject.com/en/1.7/topics/migrations/#dependencies for
more
}}}
--
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:5>
Comment (by Markush2010):
Are you working on a patch sir-sigurd? If not, I'd write one.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:6>
Comment (by sir-sigurd):
Replying to [comment:6 Markush2010]:
> Are you working on a patch sir-sigurd? If not, I'd write one.
Yes, I'm working on it.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:7>
Comment (by yuvadm):
There's an easier way to reproduce what seems to be the exact same error:
* Create a `BaseModel` and a `SubModel` that inherits from it
* Run `makemigrations` and `migrate` to add both models to database
* Delete both models together
* Run `makemigrations` and `migrate` to delete both models from the
database
The same error should now appear.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:8>
Comment (by ris):
I invite you all to look at my marked-as-duplicate bug #23818. To me it
seems there is simply no way for django's migration operations to express
a change of {{{bases}}}. {{{parent_link}}}s are created & removed, but the
built-up in-memory representation of the models never understands the new
parentage, meaning certain operations (e.g. in a RunPython operation) will
simply not work right when referring to inherited fields. This goes beyond
{{{makemigrations}}} simply not detecting a change.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:9>
* cc: bugs@… (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:10>
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:11>
* owner: sir-sigurd =>
* status: assigned => new
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:12>
* cc: ericmills2@… (added)
Comment:
This bug has burned me pretty bad. I was working through steps to switch
from concrete inheritance to abstract inheritance. Is someone going to
revisit this?
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:13>
Comment (by timgraham):
#23521 may be related or a duplicate.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:14>
Comment (by jmfederico):
Having the same issue.
I had to manually alter my initial migration and remove the offending base
class for my app to work.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:15>
Comment (by rm_):
I had the need as described in #23818 but instead of squashing migrations
i've created a migrations operator to update the bases on migrations
models state. This works fine for me on django 1.8. I still haven't tested
if django master behaves differently. Do you think this is a valuable
addition to django?
{{{
class AlterBaseOperation(Operation):
reduce_to_sql = False
reversible = True
def __init__(self, model_name, bases, prev_bases):
self.model_name = model_name
self.bases = bases
self.prev_bases = prev_bases
def state_forwards(self, app_label, state):
state.models[app_label, self.model_name].bases = self.bases
state.reload_model(app_label, self.model_name)
def state_backwards(self, app_label, state):
state.models[app_label, self.model_name].bases = self.prev_bases
state.reload_model(app_label, self.model_name)
def database_forwards(self, app_label, schema_editor, from_state,
to_state):
pass
def database_backwards(self, app_label, schema_editor, from_state,
to_state):
pass
def describe(self):
return "Update %s bases to %s" % (self.model_name, self.bases)
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:16>
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:17>
* status: assigned => new
* owner: Sergey Fedoseev => (none)
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:18>
* cc: Charlie Denton (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:19>
* cc: Ian Foote (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:20>
* owner: (none) => Ian Foote
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:21>
* has_patch: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:22>
* needs_better_patch: 0 => 1
* version: 1.7 => master
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:23>
Comment (by felixxm):
Another use case of `migrations.AlterModelBases()` is described in #30513.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:24>
* cc: Daniel Rios (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:25>
Comment (by Karolis Ryselis):
There is one more case that needs to be addressed related to bases in
migrations.
**Step 1:**
Consider this model:
{{{
class Good(GoodServiceBase):
title = models.CharField(max_length=16)
}}}
this creates migration with the following operation:
{{{
migrations.CreateModel(
name='Good',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True,
serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=16)),
],
),
}}}
**Step 2:**
Then we add a new model and change existing model to inherit from the new
model.
{{{
class GoodServiceBase(models.Model):
active = models.BooleanField(default=True)
class Good(GoodServiceBase):
title = models.CharField(max_length=16)
}}}
This generates migration like this:
{{{
migrations.CreateModel(
name='GoodServiceBase',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True,
serialize=False, verbose_name='ID')),
('active', models.BooleanField(default=True)),
],
),
migrations.RemoveField(
model_name='good',
name='id',
),
migrations.AddField(
model_name='good',
name='goodservicebase_ptr',
field=models.OneToOneField(auto_created=True, default=1,
on_delete=django.db.models.deletion.CASCADE, parent_link=True,
primary_key=True, serialize=False, to='goods.GoodServiceBase'),
preserve_default=False,
),
}}}
If we have no data in database, this will pass.
**Step 3 with crash:**
Try to access field {{{active}}} in datamigration and migration crashes.
Operation in migration to reproduce this:
{{{
def migrate_my_data(apps, schema_editor):
for good in apps.get_model("goods", "Good").objects.all():
print(good.active)
migrations.RunPython(migrate_my_data, reverse_code=lambda x, y: None)
}}}
This crashes with the error:
{{{
<...>
File "<project home>/goods/migrations/0003_auto_20191025_1157.py", line 8,
in migrate_my_data
print(good.active)
AttributeError: 'Good' object has no attribute 'active'
}}}
As far as I understand this happens because {{{bases}}} is not altered in
migration and fake models do not inherit fields from their true parent
models. Thus, currently if we change inheritance chain of existing models,
we lose the ability to use those models in data migrations.
Tested in version 2.2.6.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:26>
Comment (by felixxm):
Another two duplicates: #31329 and #26488.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:27>
Comment (by felixxm):
Another use case is described in #31343.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:28>
* owner: Ian Foote => (none)
* status: assigned => new
Comment:
Deassigning because I don't think I'm likely to get to this again in the
near future and I'd be happy for someone else to take my work and finish
the job.
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:29>
* cc: Sardorbek Imomaliev (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:30>
* owner: (none) => Zorking
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:31>
* needs_better_patch: 1 => 0
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:32>
* needs_tests: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/23521#comment:33>