Opened 6 years ago

Closed 6 years ago

#29245 closed Cleanup/optimization (fixed)

ForeignKeyField Renaming leads Remove and AddField instead of RenameField Migration

Reported by: Taqi Abbas Owned by: nobody
Component: Migrations Version: dev
Severity: Normal Keywords: ForeignKey, RenameField, db_column
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Given this field in the model:

class Answer(models.Model):
	question = models.ForeignKey(question_models.Question, on_delete=models.CASCADE, null=True, blank=True)
	...

I changed this to:

class Answer(AbstractModel):
	_question = models.ForeignKey(question_models.Question, db_column='question_id', on_delete=models.CASCADE, null=True, blank=True)
	...

the resulting migration was:

	...
        migrations.RemoveField(
            model_name='answer',
            name='question',
        ),
        migrations.AddField(
            model_name='answer',
            name='_question',
            field=models.ForeignKey(blank=True, db_column='question_id', null=True, on_delete=django.db.models.deletion.CASCADE, to='survey.Question'),
        ),
	...

whereas it should have been the following.

	...
        migrations.RenameField(
            model_name='answer',
            old_name='question',
            new_name='_question',
        ),
	...

But when I manually changed to the above, I get the following error:

ProgrammingError: column survey_answer.question_id does not exist
LINE 1: ...swer"."updated_on", "survey_answer"."is_deleted", "survey_an...
                                                             ^
HINT:  Perhaps you meant to reference the column "survey_answer._question_id".

After this, I ran makemigrations again, without changing any model and this time it made the following:

        migrations.AlterField(
            model_name='answer',
            name='_question',
            field=models.ForeignKey(blank=True, db_column='question_id', null=True, on_delete=django.db.models.deletion.CASCADE, to='survey.Question'),
        ),

The database was PostgreSQL.

Change History (3)

comment:1 by Simon Charette, 6 years ago

Triage Stage: UnreviewedAccepted
Type: BugCleanup/optimization
Version: 2.0master

The issue here is that the auto-detector won't be able to detect field renames if any other options has been changed in the mean time.

Could you confirm that the following works:

  1. Only perform the db_column='question_id' change.
  2. Run makemigrations and assert that a migration with an AlterField operation was generated to include the db_column='question_id' change.
  3. Change the attribute name from question to _question.
  4. Run makemigrations and confirm the field rename. Assert that a migration with a RenameField operation was created.

At this point both migrations should be SQL noops.

I'm accepting on the basis that the auto-detector rename logic could be enhanced to better handle db_column changes by comparing implicit db_column values to implicit ones and prompt for a rename.

comment:2 by Simon Charette, 6 years ago

Has patch: set

Someone at work hit a similar issue so I figured out I'd submit a PR tackling what I suggested above.

https://github.com/django/django/pull/9829

comment:3 by Tim Graham <timograham@…>, 6 years ago

Resolution: fixed
Status: newclosed

In 2156565b:

Fixed #29245 -- Made autodetector treat field renames + db_column addition as RenameField.

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