Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#27915 closed Bug (fixed)

Defining Index object in Meta.indexes in abstract class causes failure during migration of sub-classes

Reported by: Tommy Beadle Owned by: Tim Graham
Component: Database layer (models, ORM) Version: 1.11
Severity: Release blocker Keywords:
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

If I define an abstract model like this:

class AbstractClass(models.Model):
    text = models.TextField()
    class Meta:
        abstract=True
        indexes = [
            models.indexes.Index(fields=['text']),
        ]

and then subclass it:

class NewClass1(AbstractClass):
    pass

class NewClass2(AbstractClass):
    pass

Then, when I make the migrations, an index with the same ID is created for the sub-classes:

(venv) $ ./manage.py makemigrations myapp
Migrations for 'myapp':
  myapp/migrations/0001_initial.py
    - Create model NewClass1
    - Create model NewClass2
    - Create index myapp_abstr_text_5dfb11_idx on field(s) text of model newclass2
    - Create index myapp_abstr_text_5dfb11_idx on field(s) text of model newclass1

which then results in the following traceback when performing the migration:

(venv) $ ./manage.py migrate
<snip>
Traceback (most recent call last):                                        
  File "./manage.py", line 22, in <module>
    execute_from_command_line(sys.argv)
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/core/management/__init__.py", line 363, in execute_from_command_line
    utility.execute()
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/core/management/__init__.py", line 355, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/core/management/base.py", line 283, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/core/management/base.py", line 330, in execute
    output = self.handle(*args, **options)
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 204, in handle 
    fake_initial=fake_initial,
  File "/home/tbeadle/venv/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 "/home/tbeadle/venv/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 "/home/tbeadle/venv/lib/python3.6/site-packages/django/db/migrations/executor.py", line 244, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/home/tbeadle/venv/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 "/home/tbeadle/venv/lib/python3.6/site-packages/django/db/migrations/operations/models.py", line 785, in database_forwards
    schema_editor.add_index(model, self.index)
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 330, in add_index
    self.execute(index.create_sql(model, self))
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 119, in execute
    cursor.execute(sql, params)
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 80, in execute 
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 65, in execute 
    return self.cursor.execute(sql, params)
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/utils/six.py", line 685, in reraise
    raise value.with_traceback(tb)
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 65, in execute 
    return self.cursor.execute(sql, params)
  File "/home/tbeadle/venv/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 328, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: index myapp_abstr_text_5dfb11_idx already exists

This is apparently because the Index object gets created during creation of the abstract class and reused in the subclasses. Instead, the name needs to be generated when it gets copied to the sub-classes.

Change History (5)

comment:1 by Tim Graham, 7 years ago

Severity: NormalRelease blocker
Triage Stage: UnreviewedAccepted

comment:2 by Tim Graham, 7 years ago

Owner: changed from nobody to Tim Graham
Status: newassigned

comment:3 by Tim Graham, 7 years ago

Has patch: set

comment:4 by Tim Graham <timograham@…>, 7 years ago

Resolution: fixed
Status: assignedclosed

In 3d19d142:

Fixed #27915 -- Allowed Meta.indexes to be defined in abstract models.

Thanks Markus Holtermann for review.

comment:5 by Tim Graham <timograham@…>, 7 years ago

In e5880516:

[1.11.x] Fixed #27915 -- Allowed Meta.indexes to be defined in abstract models.

Thanks Markus Holtermann for review.

Backport of 3d19d1428a05b514afb771b52870d1f7c25670d1 from master

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