﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
22761	Migrating from an auto to natural key with foreign model and 'to' FK	jarshwah	nobody	"I've run into issues with Postgres and Oracle (so I'd assume other backends are affected) not being able to migrate a model from an auto primary key to a natural primary key, where another model has a foreign key that points at the natural.

{{{

class Recording(models.Model):
    some_key = models.PositiveIntegerField(unique=True)

class Tag(models.Model):
    recording = models.ForeignKey(Recording, to_field='some_key')

(scratchpad)smeatonj ~/Development/scratchpad $ ./manage.py makemigrations
Migrations for 'migrationstest':
  0001_initial.py:
    - Create model Recording
    - Create model Tag

class Migration(migrations.Migration):
    dependencies = [
    ]
    operations = [
        migrations.CreateModel(
            name='Recording',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('some_key', models.PositiveIntegerField(unique=True)),
            ],
            options={
            },
            bases=(models.Model,),
        ),
        migrations.CreateModel(
            name='Tag',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('recording', models.ForeignKey(to='migrationstest.Recording', to_field=b'some_key')),
            ],
            options={
            },
            bases=(models.Model,),
        ),
    ]

(scratchpad)smeatonj ~/Development/scratchpad $ ./manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: sessions, admin, scratch, debug_toolbar, sites, auth, aggregation, contenttypes, django_extensions
  Apply all migrations: migrationstest
Synchronizing apps without migrations:
  Creating tables...
  Installing custom SQL...
  Installing indexes...
Running migrations:
  Applying migrationstest.0001_initial... FAKED
(scratchpad)smeatonj ~/Development/scratchpad $

}}}

Now we change the main model to use a natural key, and remove the `to` directive of the foreign key:

{{{

# change to natural key
class Recording(models.Model):
    some_key = models.PositiveIntegerField(primary_key=True)

class Tag(models.Model):
    recording = models.ForeignKey(Recording)

(scratchpad)smeatonj ~/Development/scratchpad $ ./manage.py makemigrations
Migrations for 'migrationstest':
  0002_auto_20140604_0806.py:
    - Remove field id from recording
    - Alter field some_key on recording

class Migration(migrations.Migration):

    dependencies = [
        ('migrationstest', '0001_initial'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='recording',
            name='id',
        ),
        migrations.AlterField(
            model_name='recording',
            name='some_key',
            field=models.PositiveIntegerField(serialize=False, primary_key=True),
        ),
    ]


(scratchpad)smeatonj ~/Development/scratchpad $ ./manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: sessions, admin, scratch, debug_toolbar, sites, auth, aggregation, contenttypes, django_extensions
  Apply all migrations: migrationstest
Synchronizing apps without migrations:
  Creating tables...
  Installing custom SQL...
  Installing indexes...
Running migrations:
  Applying migrationstest.0002_auto_20140604_0806...Traceback (most recent call last):
  File ""./manage.py"", line 9, in <module>
    execute_from_command_line(sys.argv)
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/core/management/__init__.py"", line 427, in execute_from_command_line
    utility.execute()
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/core/management/__init__.py"", line 419, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/core/management/base.py"", line 288, in run_from_argv
    self.execute(*args, **options.__dict__)
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/core/management/base.py"", line 337, in execute
    output = self.handle(*args, **options)
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/core/management/commands/migrate.py"", line 146, in handle
    executor.migrate(targets, plan, fake=options.get(""fake"", False))
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/db/migrations/executor.py"", line 62, in migrate
    self.apply_migration(migration, fake=fake)
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/db/migrations/executor.py"", line 96, in apply_migration
    migration.apply(project_state, schema_editor)
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/db/migrations/migration.py"", line 107, in apply
    operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/db/migrations/operations/fields.py"", line 132, in database_forwards
    schema_editor.alter_field(from_model, from_field, to_field)
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/db/backends/schema.py"", line 508, in alter_field
    ""name"": constraint_name,
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/db/backends/schema.py"", line 98, in execute
    cursor.execute(sql, params)
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/db/backends/utils.py"", line 81, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/db/backends/utils.py"", line 65, in execute
    return self.cursor.execute(sql, params)
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/db/utils.py"", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File ""/Users/smeatonj/Development/.virtualenvs/scratchpad/lib/python2.7/site-packages/django/db/backends/utils.py"", line 65, in execute
    return self.cursor.execute(sql, params)
django.db.utils.InternalError: cannot drop constraint migrationstest_recording_some_key_key on table migrationstest_recording because other objects depend on it
DETAIL:  constraint b25f2749e675737f4ae4891ed60d858c on table migrationstest_tag depends on index migrationstest_recording_some_key_key
HINT:  Use DROP ... CASCADE to drop the dependent objects too.

}}}

It blows up in Oracle too:

{{{

Traceback (most recent call last):
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/backends/utils.py"", line 65, in execute
    return self.cursor.execute(sql, params)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/backends/oracle/base.py"", line 884, in execute
    return self.cursor.execute(query, self._param_generator(params))
cx_Oracle.DatabaseError: ORA-02273: this unique/primary key is referenced by some foreign keys


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 ""/vagrant/venv/lib/python3.3/site-packages/django/core/management/__init__.py"", line 427, in execute_from_command_line
    utility.execute()
  File ""/vagrant/venv/lib/python3.3/site-packages/django/core/management/__init__.py"", line 419, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/core/management/base.py"", line 288, in run_from_argv
    self.execute(*args, **options.__dict__)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/core/management/base.py"", line 337, in execute
    output = self.handle(*args, **options)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/core/management/commands/migrate.py"", line 146, in handle
    executor.migrate(targets, plan, fake=options.get(""fake"", False))
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/migrations/executor.py"", line 62, in migrate
    self.apply_migration(migration, fake=fake)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/migrations/executor.py"", line 96, in apply_migration
    migration.apply(project_state, schema_editor)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/migrations/migration.py"", line 107, in apply
    operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/migrations/operations/fields.py"", line 132, in database_forwards
    schema_editor.alter_field(from_model, from_field, to_field)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/backends/oracle/schema.py"", line 49, in alter_field
    super(DatabaseSchemaEditor, self).alter_field(model, old_field, new_field, strict)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/backends/schema.py"", line 508, in alter_field
    ""name"": constraint_name,
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/backends/schema.py"", line 98, in execute
    cursor.execute(sql, params)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/backends/utils.py"", line 81, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/backends/utils.py"", line 65, in execute
    return self.cursor.execute(sql, params)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/utils.py"", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/utils/six.py"", line 549, in reraise
    raise value.with_traceback(tb)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/backends/utils.py"", line 65, in execute
    return self.cursor.execute(sql, params)
  File ""/vagrant/venv/lib/python3.3/site-packages/django/db/backends/oracle/base.py"", line 884, in execute
    return self.cursor.execute(query, self._param_generator(params))
django.db.utils.DatabaseError: ORA-02273: this unique/primary key is referenced by some foreign keys

}}}
"	Bug	new	Migrations	1.7	Normal		migrations		Accepted	0	0	0	0	0	0
