Opened 8 years ago

Closed 8 years ago

#27297 closed Bug (duplicate)

infinite AlterField migrations created for foreign key after case-only model name change

Reported by: Daniel Musketa Owned by: nobody
Component: Migrations Version: dev
Severity: Normal Keywords:
Cc: daniel.musketa@…, desecho@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Daniel Musketa)

Tested and affected Django versions:

  • 1.7
  • 1.8
  • 1.9
  • 1.9.6
  • 1.10.1

A case-only rename of a model is not detected. This leads to infinite migrations on a foreign key field that refers to the renamed model.

I created a minimal working example to reproduce this
behaviour: https://github.com/vlt/django_ticket_27297_capitalization

When you run ./manage.py makemigrations it will create
the following migration over and over again:

Migrations for 'app1':
  app1/migrations/0003_auto_20161001_2136.py:
    - Alter field fk_to_model1 on model2

The new file 0003_auto_20161001_2136.py:

# -*- coding: utf-8 -*-
# Generated by Django 1.10.2 on 2016-10-01 21:36
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        ('app1', '0002_model2'),
    ]

    operations = [
        migrations.AlterField(
            model_name='model2',
            name='fk_to_model1',
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app1.moDEl1'),
        ),
    ]

I have no idea why the Autodetector in migrations uses lower() in the first place.

Change History (10)

comment:1 by Daniel Musketa, 8 years ago

Cc: daniel.musketa@… added
Description: modified (diff)

I tested with several other versions and got the following weirdly unpredictable behaviour:

(django_1.7) $  for _ in {{1..10}}; do ./manage.py makemigrations; done
Migrations for 'app1':
  0003_auto_20160929_2012.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0004_auto_20160929_2012.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0005_auto_20160929_2012.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0006_auto_20160929_2012.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0007_auto_20160929_2012.py:
    - Alter field fk_to_model1 on model2
No changes detected
Migrations for 'app1':
  0008_auto_20160929_2012.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0009_auto_20160929_2012.py:
    - Alter field fk_to_model1 on model2
No changes detected
No changes detected
(django_1.8)$ for _ in {{1..20}}; do ./manage.py makemigrations; done
No changes detected
No changes detected
Migrations for 'app1':
  0003_auto_20160929_1957.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0004_auto_20160929_1957.py:
    - Alter field fk_to_model1 on model2
No changes detected
Migrations for 'app1':
  0005_auto_20160929_1957.py:
    - Alter field fk_to_model1 on model2
No changes detected
No changes detected
Migrations for 'app1':
  0006_auto_20160929_1957.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0007_auto_20160929_1957.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0008_auto_20160929_1957.py:
    - Alter field fk_to_model1 on model2
No changes detected
Migrations for 'app1':
  0009_auto_20160929_1957.py:
    - Alter field fk_to_model1 on model2
No changes detected
No changes detected
No changes detected
Migrations for 'app1':
  0010_auto_20160929_1957.py:
    - Alter field fk_to_model1 on model2
No changes detected
No changes detected
Migrations for 'app1':
  0011_auto_20160929_1957.py:
    - Alter field fk_to_model1 on model2
(django_1.9)$ for _ in {{1..10}}; do ./manage.py makemigrations; done
Migrations for 'app1':
  0003_auto_20160929_2010.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0004_auto_20160929_2010.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0005_auto_20160929_2010.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0006_auto_20160929_2010.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0007_auto_20160929_2010.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0008_auto_20160929_2010.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0009_auto_20160929_2010.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0010_auto_20160929_2010.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0011_auto_20160929_2010.py:
    - Alter field fk_to_model1 on model2
Migrations for 'app1':
  0012_auto_20160929_2010.py:
    - Alter field fk_to_model1 on model2

comment:2 by Tim Graham, 8 years ago

Summary: makemigrations creates the same migration again and again (because it fails to compare uppercase to lowercase model names)Non-deterministic infinite AlterField migrations created for foreign key
Triage Stage: UnreviewedAccepted

I'm not sure about the cause, but the root issue is that deconstruction is returning non-deterministic results. Sometimes the fields appear equal and sometimes the case differs in the to field, as you said.

comment:3 by Baptiste Mispelon, 8 years ago

I think the issue might be caused by the name='model1', in the initial migration.

When I generate the migrations, I get name='Model1', (notice the difference in the capitalization of the model).

How did you generate the initial migration?

I noticed that if I start with class model1(models.Model): ..., create the initial migration, change to class Model1(models.Model): ..., then makemigrations won't detect any changes. Is it possible you changed the name of Model1 in the same way?

in reply to:  3 comment:4 by Daniel Musketa, 8 years ago

Replying to Baptiste Mispelon:

Is it possible you changed the name of Model1 in the same way?

Yes, you’re absolutely right. In the actual project there was first

class adress(models.Model) (sic!), then
class address(models.Model) and then finally
class Address(models.Model).

In the migration files it looks like this:

class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='adress',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
            ],
        ),
    ]

and then

class Migration(migrations.Migration):

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

    operations = [
        migrations.RenameModel(
            old_name='adress',
            new_name='address',
        ),
    ]

But then no new change is detected. I tested a rename from adress to Address which results in a capitalized new_name='Address', and everything should be fine.

So, the actual problem might be the rename from a lowercase to capfirst model name. This is not detected by makemigrations which seems to compare everything .lower()’d.

This doesn’t explain though why changes are detected in only some of my for loop makemigrations runs. ;-)

Propably related to #22608?

comment:5 by Daniel Musketa, 8 years ago

Description: modified (diff)
Summary: Non-deterministic infinite AlterField migrations created for foreign keyinfinite AlterField migrations created for foreign key after case-only model name change

I narrowed down the cause, created a new example and changed the ticket description accordingly.

comment:6 by Daniel Musketa, 8 years ago

Description: modified (diff)

comment:7 by Anton Samarchyan, 8 years ago

Cc: desecho@… added
Has patch: set
Version: 1.10master

Added PR 7469 - Ignore case-only model name changes in migration autodetector

comment:8 by Simon Charette, 8 years ago

Patch needs improvement: set

Left some comments on the PR.

comment:9 by Anton Samarchyan, 8 years ago

Has patch: unset
Patch needs improvement: unset

My patch used an incorrect approach. Need a new patch.

comment:10 by Simon Charette, 8 years ago

Resolution: duplicate
Status: newclosed

Duplicate of #23916.

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