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

Posted

技术标签:

【中文标题】从 South 迁移到 Django 1.7 迁移:可交换依赖项【英文标题】:Moving from South to Django 1.7 migrations: swappable dependency 【发布时间】:2015-04-12 09:04:06 【问题描述】:

我有一个用 Django 1.6 编写的项目,它使用南迁移,我试图将它移到 Django 1.7。所以我从here指示的说明开始。

    INSTALLED_APPS 中删除south。 删除了旧的迁移文件。 跑./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

【问题讨论】:

【参考方案1】:

我的错误是运行./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

所以我不得不:

    复制上次迁移的内容:

    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 makemigrations userprofile --empty。 粘贴并运行./manage.py migrate userprofile --fake

【讨论】:

以上是关于从 South 迁移到 Django 1.7 迁移:可交换依赖项的主要内容,如果未能解决你的问题,请参考以下文章

无法将 Django 从 1.7 迁移到 1.8

从 1.5 迁移到 1.7 时的单元测试警告

makemigrations 和升级到 Django 1.7 的问题

无法在 Django 1.7 中创建 South 数据库模型

South - 将 django 应用程序从 sqlite 迁移到 mysql

如何在 Django 中使用 South 将数据从一个模型迁移到另一个模型?