在django迁移时如何设置/提供默认值?

时间:2018-03-11 15:13:34

标签: django django-models django-migrations

方案
 我有一个模型Customer

class Customer(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()
    company = models.CharField(max_length=100)


现在我更新了company属性与ForeignKey关系如下,

class Company(models.Model):
    name = models.CharField(max_length=100)
    location = models.CharField(max_length=100)


class Customer(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()
    company = models.ForeignKey(Company)



我需要的是,当新的迁移应用于数据库时,相应的Company实例必须自动生成并映射到company实例的Customer属性。

那可能吗?我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:3)

让我们从原始模型开始,一步一步地完成。

class Customer(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()
    company = models.CharField(max_length=100)

首先,你必须保留原始字段并创建一个新字段,以便能够在之后恢复旧数据。

class Customer(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()
    company = models.CharField(max_length=100)
    _company = models.ForeignKey(Company)

现在,您可以使用manage.py makemigrations创建第一次迁移。然后你必须创建一个data migration。使用manage.py makemigrations yourapp --empty创建迁移并更新生成的文件:

from django.db import migrations

def export_customer_company(apps, schema_editor):
    Customer = apps.get_model('yourapp', 'Customer')
    Company = apps.get_model('yourapp', 'Company')
    for customer in Customer.objects.all():
        customer._company = Company.objects.get_or_create(name=customer.company)[0]
        customer.save()

def revert_export_customer_company(apps, schema_editor):
    Customer = apps.get_model('yourapp', 'Customer')
    Company = apps.get_model('yourapp', 'Company')
    for customer in Customer.objects.filter(_company__isnull=False):
        customer.company = customer._company.name
        customer.save()

class Migration(migrations.Migration):

    dependencies = [
        ('yourapp', 'xxxx_previous_migration'),  # Note this is auto-generated by django
    ]

    operations = [
        migrations.RunPython(export_customer_company, revert_export_customer_company),
    ]

上述迁移将根据Company填充您的Customer._company模型和Customer.company字段。

现在,您可以删除旧Customer.company并重命名Customer._company

class Customer(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()
    company = models.ForeignKey(Company)

最终manage.py makemigrationsmanage.py migrate

答案 1 :(得分:2)

当然,但是您必须进行三次迁移,并且这些字段的名称不能同时存在,因为两者都需要同时存在。如果您已经删除了真实数据库中的公司字段,那么您就是SOL,并且必须手动修复它们。

首先,在正常的数据库迁移中添加Company模型,然后执行数据迁移并在第一次数据库迁移后运行,然后执行另一个数据库迁移,从Customer中删除公司字段模型。

您可以像往常一样使用manage.py makemigrations进行数据库迁移,只需在它们之间的迁移文件中添加如下内容,此处我将新公司ForeignKey字段命名为company_obj

def fix_companies(apps, schema_editor):
    Company = apps.get_model("myapp", "Company")
    Customer = apps.get_model("myapp", "Customer")
    for c in Customer.objects.all():
        company, _ = Company.objects.get_or_create(name=c.name)
        c.company_obj = company
        c.save()


def rev(apps, schema_editor):
    # the reverse goes here if you want to copy company names into customer again if you migrate backwards.
    pass

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', 'XXXX_migration_that_added_company_model'),
    ]

    operations = [
        migrations.RunPython(fix_companies, rev),
    ]