从 South 迁移到 Django 1.7 迁移:可交换依赖

Moving from South to Django 1.7 migrations: swappable dependency

我有一个用 Django 1.6 编写的项目,它使用 South 迁移,我试图将它移动到 Django 1.7。所以我从 here.

指示的说明开始
  1. 已从 INSTALLED_APPS 中删除 south
  2. 删除了旧的迁移文件。
  3. 运行 ./manage.py makemigrations.

此时我得到了django.db.migrations.graph.CircularDependencyError

这是我的模型:

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,
    )

这在 customer 应用程序的初始迁移中导致了可交换的依赖项:

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

根据建议 here,我编辑了 userprofile 的初始迁移并注释了与客户相关的行:

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,),
        ),
    ]

运行 ./manage.py migrate 并创建了另一个添加客户字段的迁移:

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,
        ),
    ]

但是当我运行./manage.py migrate userprofile --fake时,我得到一个错误

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.

另一方面,如果没有此迁移,我的测试会失败:

OperationalError: no such table: userprofile_user_customers

我的错误是运行./manage.py makemigrations userprofile,而不是运行宁./manage.py makemigrations userprofile --empty。在第一种情况下,Django 将其理解为添加 contracts 字段(确实如此)的迁移,对于第二种情况,如果我 运行 ./manage.py migrate userprofile 它失败并显示:

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

所以我不得不:

  1. 复制上次迁移的内容:

    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. 删除那个迁移。

  3. 运行 ./manage.py makemigrations userprofile --empty.
  4. 粘贴并运行./manage.py migrate userprofile --fake