Ticket #235 (closed defect: fixed)

Opened 5 years ago

Last modified 3 years ago

adding unique=True to a field that formerly had db_index=True, autodetection fails

Reported by: carl@… Owned by: andrew
Priority: major Milestone: 0.7
Component: migrations Version: 0.6
Keywords: Cc:

Description

Create a model like this (in myapp/models.py):

class TestModel(models.Model):
    slug = models.SlugField()

Perform its initial migration. Then add unique=True:

class TestModel(models.Model):
    slug = models.SlugField(unique=True)

Auto-create a migration:

$ ./manage.py startmigration myapp --auto unique_slug

And run the migration:

$ ./manage.py migrate myapp
Running migrations for myapp:
 - Migrating forwards to 0002_unique_slug.
 > myapp: 0002_unique_slug
Traceback (most recent call last):
  File "/home/carljm/projects/testproj_env/bin/django-admin.py", line 7, in <module>
    execfile(__file__)
  File "/home/carljm/projects/testproj_env/src/django/django/bin/django-admin.py", line 5, in <module>
    management.execute_from_command_line()
  File "/home/carljm/projects/testproj_env/src/django/django/core/management/__init__.py", line 353, in execute_from_command_line
    utility.execute()
  File "/home/carljm/projects/testproj_env/src/django/django/core/management/__init__.py", line 303, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/carljm/projects/testproj_env/src/django/django/core/management/base.py", line 195, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/home/carljm/projects/testproj_env/src/django/django/core/management/base.py", line 222, in execute
    output = self.handle(*args, **options)
  File "/home/carljm/projects/testproj_env/src/south/south/management/commands/migrate.py", line 91, in handle
    skip = skip,
  File "/home/carljm/projects/testproj_env/src/south/south/migration.py", line 581, in migrate_app
    result = run_forwards(mapp, [mname], fake=fake, db_dry_run=db_dry_run, verbosity=verbosity)
  File "/home/carljm/projects/testproj_env/src/south/south/migration.py", line 388, in run_forwards
    verbosity = verbosity,
  File "/home/carljm/projects/testproj_env/src/south/south/migration.py", line 329, in run_migrations
    runfunc(orm)
  File "/home/carljm/projects/testproj/content/migrations/0002_unique_slug.py", line 11, in forwards
    db.create_unique('myapp_testmodel', ['slug'])
  File "/home/carljm/projects/testproj_env/src/south/south/db/generic.py", line 358, in create_unique
    self.execute("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE (%s)" % (qn(table_name), qn(name), cols))
  File "/home/carljm/projects/testproj_env/src/south/south/db/generic.py", line 82, in execute
    cursor.execute(sql, params)
  File "/home/carljm/projects/testproj_env/src/django/django/db/backends/util.py", line 19, in execute
    return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: relation "myapp_testmodel_slug" already exists

The problem is that an index myapp_testmodel_slug already existed for the db_index=True (which SlugFields? have on by default), and the generated migration tries to create a new unique index with the same name, without deleting the old one.

The manual fix is to add

db.delete_index('myapp_testmodel', ['slug'])

to the beginning of the migration's "forwards" method (before the new unique index is created), and likewise

db.create_index('myapp_testmodel', ['slug'])

to the end of the "backwards" method. But it would be nice if South figured this out itself.

(The problem is the same if the field is not a SlugField? and db_index=True is explicitly specified in the first version of the model.)

Change History

comment:1 Changed 5 years ago by andrew

  • Status changed from new to assigned
  • Milestone set to 0.7

Yes, this is the old problem about indexes, uniques, MySQL, and various other things like that. I'm scheduling this for 0.7 to fix it, since there's thankfully a workaround.

comment:2 Changed 5 years ago by carl@…

Just a note since you mentioned MySQL: I originally had this problem with Postgres (note psycopg2 in the traceback above), and I just now experienced it with MySQL, so it's at least an issue on those two DB backends, if not others as well.

comment:3 Changed 5 years ago by andrew

  • Status changed from assigned to closed
  • Resolution set to fixed

This appears to be fixed in 0.7.

Note: See TracTickets for help on using tickets.