Opened 10 years ago

Closed 10 years ago

#21664 closed Bug (fixed)

Migrations and "Multi-Table" Inheritance

Reported by: andrew.ngo@… Owned by: Andrew Godwin
Component: Migrations Version: dev
Severity: Normal Keywords: migration inheritance
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Summary

I'm not entirely familiar with the internal workings of "Synchronize unmigrated apps:" but my (freshly created) app doesn't seem to appear in the list of unmigrated apps. Maybe this is how it's supposed to work?

Anyway, when the time comes to create all the new models through the "Apply all migrations:" portion, the migration mechanism chokes on creating inherited models if it has just created the base model.

Steps to Recreate

I create an app "digestive", add it to INSTALLED_APPS in settings.py, and give it the following two models (one inheriting from the other).

# models.py
from django.db import models

class Liver(models.Model):
    pass

class DiseasedLiver(Liver):
    ttl = models.PositiveIntegerField()

Then I run syncdb. It tells me that I should run makemigrations.

Operations to perform:
  Synchronize unmigrated apps: admin, contenttypes, auth, sessions
  Apply all migrations: (none)

  [...]

  No migrations needed.
  Your models have changes that are not yet reflected in a migration, and so won't be applied.
  Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.

I run makemigrations, then migrate. This is the migration file it generates.

# 0001_initial.py
from django.db import models, migrations

class Migration(migrations.Migration):
    
    dependencies = []

    operations = [
        migrations.CreateModel(
            fields = [('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True),)],
            bases = (models.Model,),
            options = {},
            name = 'Liver',
        ),
        migrations.CreateModel(
            fields = [('liver_ptr', ('ttl', models.PositiveIntegerField(),)],
            bases = ('digestive.liver',),
            options = {},
            name = 'DiseasedLiver',
        ),
    ]

I run syncdb again. This is the output.

Operations to perform:
  Synchronize unmigrated apps: admin, contenttypes, auth, sessions
  Apply all migrations: digestive

  [...]

Running migrations:
  Applying digestive.0001_initial...Traceback (most recent call last):
  File "/django/db/backends/utils.py", line 61, in execute
    return self.cursor.execute(sql, params)
  File "/django/db/backends/sqlite3/base.py", line 489, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: duplicate column name: liver_ptr_id

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/django/core/management/__init__.py", line 423, in execute_from_command_line
    utility.execute()
  File "/django/core/management/__init__.py", line 415, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/django/core/management/base.py", line 243, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/django/core/management/base.py", line 290, in execute
    output = self.handle(*args, **options)
  File "/django/core/management/base.py", line 429, in handle
    return self.handle_noargs(**options)
  File "/django/core/management/commands/syncdb.py", line 22, in handle_noargs
    call_command("migrate", **options)
  File "/django/core/management/__init__.py", line 170, in call_command
    return klass.execute(*args, **defaults)
  File "/django/core/management/base.py", line 290, in execute
    output = self.handle(*args, **options)
  File "/django/core/management/commands/migrate.py", line 145, in handle
    executor.migrate(targets, plan, fake=options.get("fake", False))
  File "/django/db/migrations/executor.py", line 60, in migrate
    self.apply_migration(migration, fake=fake)
  File "/django/db/migrations/executor.py", line 94, in apply_migration
    migration.apply(project_state, schema_editor)
  File "/django/db/migrations/migration.py", line 97, in apply
    operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
  File "/django/db/migrations/operations/models.py", line 26, in database_forwards
    schema_editor.create_model(model)
  File "/django/db/backends/schema.py", line 233, in create_model
    self.execute(sql, params)
  File "/django/db/backends/schema.py", line 95, in execute
    cursor.execute(sql, params)
  File "/django/db/backends/utils.py", line 77, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/django/db/backends/utils.py", line 61, in execute
    return self.cursor.execute(sql, params)
  File "/django/db/utils.py", line 93, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/django/utils/six.py", line 495, in reraise
    raise value.with_traceback(tb)
  File "/django/db/backends/utils.py", line 61, in execute
    return self.cursor.execute(sql, params)
  File "/django/db/backends/sqlite3/base.py", line 489, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: duplicate column name: liver_ptr_id

Change History (3)

comment:1 by andrew.ngo@…, 10 years ago

Severity: Release blockerNormal

Workaround: comment out submodels, run makemigrations, uncomment submodels, run makemigrations again. (Then syncdb/migrate).

comment:2 by Andrew Godwin, 10 years ago

Owner: set to Andrew Godwin
Status: newassigned

comment:3 by Andrew Godwin <andrew@…>, 10 years ago

Resolution: fixed
Status: assignedclosed

In 3f1a008266e8797ae104905b4d3168fa2a33b9ae:

Fixed #21664: Multi-table inheritance was duplicating _ptr fields

Note: See TracTickets for help on using tickets.
Back to Top