Opened 7 years ago

Closed 10 months ago

#28056 closed Bug (duplicate)

Reverse migration for model rename with cross-app ForeignKey fails

Reported by: Paul Tiplady Owned by: Bhuvnesh
Component: Migrations Version: 1.10
Severity: Normal Keywords:
Cc: Friedrich Delgado Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

When attempting to reverse a migration for the rename of a model, where the model has ForeignKey references to it from models in other apps, the reverse migration fails with the following error:

ValueError: The field <foreignkey_field> was declared with a lazy reference to '<old_model_name>', but app 'one' doesn't provide model '<old_model_name>'

I've put a simple repro up on github here: https://github.com/paultiplady/django-migration-bug, but here's an outline of the problem:

With two apps, one and two, and the models:

one/models.py:

from django.db import models


class Rename1(models.Model):
    pass

two/models.py:

from django.db import models


class Related2(models.Model):
    rename1 = models.ForeignKey('one.Rename1')

Renaming Rename1 to Rename2 produces a simple migration:

0002_auto_20170408_1617.py:

class Migration(migrations.Migration):

    dependencies = [
        ('one', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel(
            old_name='Rename1',
            new_name='Rename2',
        ),
    ]

But when this migration is reversed, the error is raised:

ValueError: The field two.Related2.rename1 was declared with a lazy reference to 'one.rename1', but app 'one' doesn't provide model 'rename1'.

It's unclear from the error message how I'd even go about attempting to address this problem, and the docs don't mention anything about handling this case (as far as I can tell).

Expected behaviour is to be able to handle this reverse-rename seamlessly, or at least provide a sensible error message if this operation is unsupported.

Naively it looks like the problem is that the two.Related2 model has not been given its own migration when its ForeignKey was changed from one.Rename1 to one.Rename2, instead that change is tracked implicitly and incorrectly in the RenameModel step.

Change History (10)

comment:1 by Gaurav Sehgal, 7 years ago

Owner: changed from nobody to Gaurav Sehgal
Status: newassigned

comment:2 by Tim Graham, 7 years ago

Triage Stage: UnreviewedAccepted

I think the problem is in ForeignKey.db_type(). It uses self.target_field which is using the state of the current model files rather than migration's state.

comment:3 by Gaurav Sehgal, 7 years ago

Can't we have a different migration for rename1 as alterfield, so that its migration's state handled properly.

comment:6 by Tim Graham, 7 years ago

Patch needs improvement: set

As described on the pull request, based on my testing, the patch doesn't solve the issue.

comment:7 by Friedrich Delgado, 5 years ago

Cc: Friedrich Delgado added

comment:8 by Bhuvnesh, 16 months ago

I think this issue was solved due to aa4acc164d1247c0de515c959f7b09648b57dc42 and can be closed now.

Last edited 16 months ago by Bhuvnesh (previous) (diff)

comment:9 by Bhuvnesh, 10 months ago

Owner: set to Bhuvnesh

comment:10 by Bhuvnesh, 10 months ago

There seems to be some problem with this ticket, I wasn't able to reproduce with django v1.10.7 as described above. I played with the sample repo provided and observed that the error :

ValueError: The field two.Related2.rename1 was declared with a lazy reference to 'one.rename1', but app 'one' doesn't provide model 'rename1'.

is produced when we run makemigrations command again after the RenameModel migration file is generated. I think at that time django didn't had the functionality to rename the cross-app referenced models, we can solve this by editing the migration file two.0001_initial and set the fk to "one.rename2" - removes the ValueError .

Another error:

ValueError: Related model 'one.Rename1' cannot be resolved

is thrown on migrating which is removed if we add a field instead of "pass" inside one.rename1 model.

comment:11 by Mariusz Felisiak, 10 months ago

Resolution: duplicate
Status: assignedclosed

Good catch! ('two', '0001_initial') dependency was missing in migration generated in Django < 2.0,

Duplicate of #28493, fixed by 0891503fad458e7dfabc5adbf314f80e78e63f14.

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