Opened 3 years ago

Last modified 8 months ago

#23521 new Bug

removal of concrete Model from bases doesn't remove it from ModelState bases

Reported by: Sergey Fedoseev Owned by:
Component: Migrations Version: 1.7
Severity: Normal Keywords:
Cc: info+coding@…, bugs@…, ericmills2@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Markus Holtermann)

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

Change History (16)

comment:1 Changed 3 years ago by Sergey Fedoseev

Component: UncategorizedMigrations
Type: UncategorizedBug

comment:2 Changed 3 years ago by Baptiste Mispelon

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.

comment:3 in reply to:  2 Changed 3 years ago by Sergey Fedoseev

Replying to bmispelon:

Hi,

Probably this is not obvious, but removal of Thing model from models.py, not only from SuperThing bases was implied.


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 =)

comment:4 Changed 3 years ago by Baptiste Mispelon

Triage Stage: UnreviewedAccepted

Thanks, that's the bit I was missing.

comment:5 Changed 3 years ago by Markus Holtermann

Cc: info+coding@… added
Description: modified (diff)

comment:6 Changed 3 years ago by Markus Holtermann

Are you working on a patch sir-sigurd? If not, I'd write one.

comment:7 in reply to:  6 Changed 3 years ago by Sergey Fedoseev

Replying to Markush2010:

Are you working on a patch sir-sigurd? If not, I'd write one.

Yes, I'm working on it.

comment:8 Changed 3 years ago by Yuval Adam

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.

comment:9 Changed 3 years ago 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_links 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.

comment:10 Changed 3 years ago by ris

Cc: bugs@… added

comment:13 Changed 23 months ago by Eric Mills

Cc: ericmills2@… added

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?

comment:14 Changed 20 months ago by Tim Graham

#26488 may be related or a duplicate.

Last edited 20 months ago by Markus Holtermann (previous) (diff)

comment:15 Changed 20 months ago by Federico Jaramillo Martínez

Having the same issue.
I had to manually alter my initial migration and remove the offending base class for my app to work.

comment:16 Changed 12 months ago 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)

comment:17 Changed 8 months ago by Sergey Fedoseev

Status: newassigned

comment:18 Changed 8 months ago by Sergey Fedoseev

Owner: Sergey Fedoseev deleted
Status: assignednew
Note: See TracTickets for help on using tickets.
Back to Top