2
votes

I have a project written with Django 1.6 and that uses South migrations, and I trying to move it to Django 1.7. So I started from the instructions indicated here.

  1. Deleted south from INSTALLED_APPS.
  2. Removed old migrations files.
  3. Ran ./manage.py makemigrations.

At this point I got django.db.migrations.graph.CircularDependencyError.

Here are my models:

customer.models.py:

class Customer(models.Model):
    name = models.CharField(
        max_length=128,
    )

class Department(models.Model):
    customer = models.ForeignKey(
        'customer.Customer',
        related_name='departments',
    )
    name = models.CharField(
        max_length=64,
    )

class Representative(models.Model):
    user = models.ForeignKey(
        'userprofile.User',
        related_name='representatives',
    )
    department = models.ForeignKey(
        'customer.Department',
        related_name='representatives',
    )

userprofile.models.py:

class User(AbstractBaseUser, PermissionsMixin):
    customers = models.ManyToManyField(
        'customer.Customer',
        blank=True,
        null=True,
    )

That caused in initial migration for customer application a swappable dependency:

dependencies = [
    migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

As it was recommended here, I edited initial migration for userprofile and commented lines related with customer:

class Migration(migrations.Migration):

    dependencies = [
        ('auth', '0001_initial'),
        #('customer', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='User',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('first_name', models.CharField(max_length=128, error_messages={b'min_length': 'El campo "Nombres" debe tener al menos %(limit_value)d caracteres (actualmente tiene %(show_value)d).'}, verbose_name='nombres', validators=[django.core.validators.MinLengthValidator(3)])),
                ('last_name', models.CharField(max_length=128, error_messages={b'min_length': 'El campo "Apellidos" debe tener al menos %(limit_value)d caracteres (actualmente tiene %(show_value)d).'}, verbose_name='apellidos', validators=[django.core.validators.MinLengthValidator(3)])),
                ('email', models.EmailField(unique=True, max_length=75, verbose_name='correo electr\xf3nico')),
                #('customers', models.ManyToManyField(to='customer.Customer', null=True, verbose_name='clientes relacionados', blank=True)),
            ],
            bases=(models.Model,),
        ),
    ]

ran ./manage.py migrate and created another migration that adds a customer field:

class Migration(migrations.Migration):

    dependencies = [
        ('customer', '0001_initial'),
        ('userprofile', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='user',
            name='customers',
            field=models.ManyToManyField(to='customer.Customer', null=True, verbose_name='clientes relacionados', blank=True),
            preserve_default=True,
        ),
    ]

But when I run ./manage.py migrate userprofile --fake, I get an error

Running migrations:
  No migrations to apply.
  Your models have changes that are not yet reflected in a migration, and so won't be applied.
  Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.

On the other hand, without this migration my tests fail:

OperationalError: no such table: userprofile_user_customers
1

1 Answers

2
votes

My error was to run ./manage.py makemigrations userprofile, instead of running ./manage.py makemigrations userprofile --empty. In the first case Django understood it like a migration that adds contracts field (which it is) and for the second case, if I ran ./manage.py migrate userprofile it fails with:

django.db.utils.ProgrammingError: relation "userprofile_user_customers" already exists

So I had to:

  1. Copy the content of the last migration:

    class Migration(migrations.Migration):
    
        dependencies = [
            ('customer', '0001_initial'),
            ('userprofile', '0001_initial'),
        ]
    
        operations = [
            migrations.AddField(
                model_name='user',
                name='customers',
                field=models.ManyToManyField(to='customer.Customer', null=True, verbose_name='clientes relacionados', blank=True),
                preserve_default=True,
            ),
        ]
    
  2. Delete that migration.

  3. Run ./manage.py makemigrations userprofile --empty.
  4. Paste and run ./manage.py migrate userprofile --fake.