在保留数据的同时将 Django 外键移动到另一个模型?

我有一个 Django 应用程序,其中有一个基本用户模型和用户配置文件模型。


class Office(models.Model):

    name = models.CharField()


class User(models.Model):

    email = models.EmailField()

    offices = models.ManyToManyField(Office)


class Profile(models.Model):

    user = models.OneToOneField(User)

每个用户都有一个配置文件,可以分配给许多不同的办公室。


我想要做的是拥有它,以便用户可以拥有多个配置文件,但配置文件可以分配给不同的办公室。


目前,这是不可能的,因为 Office 字段是在用户级别而不是配置文件级别分配的。我设想了 2 种方法来解决这个问题:


想办法将该offices字段移到配置文件字段。


创建一个新模型,其中ProfileNoUser包含用户模型的外键以及offices其中的外键。


您认为哪个选项最好?如果#1,我该怎么做?


叮当猫咪
浏览 78回答 1
1回答

Cats萌萌

您的问题是关于数据迁移吗?如果是这样,您应该阅读链接的文档。在我看来,您的第一个提案确实是最好的。这是如何做的。第 1 步:对模型进行更改您更改模型以匹配您的目标:# models.pyfrom django.db import modelsclass Office(models.Model):    name = models.CharField(max_length=1000)class User(models.Model):    email = models.EmailField()class Profile(models.Model):    user = models.OneToOneField(User, on_delete=models.CASCADE)    offices = models.ManyToManyField(Office)运行makemigrations:(.venv) ~/c/s/m/mysite> ./manage.py makemigrations Migrations for 'so':  so/migrations/0002_auto_20200825_1311.py    - Remove field offices from user    - Add field offices to profile第 2 步:编辑迁移文件以迁移现有数据打开上一步创建的文件。它看起来像:# Generated by Django 3.1 on 2020-08-25 13:11from django.db import migrations, modelsclass Migration(migrations.Migration):    dependencies = [        ('so', '0001_initial'),    ]    operations = [        migrations.RemoveField(            model_name='user',            name='offices',        ),        migrations.AddField(            model_name='profile',            name='offices',            field=models.ManyToManyField(to='so.Office'),        ),    ]你需要在这里做两件事:您可以看到,对于 Django 生成的命令,它将首先删除旧的 FK,然后添加新的。你应该改变它,所以它是相反的。然后你将不得不编写一些 python 代码,迁移将在正确的时间执行正确的时间是在创建新 FK 之后和旧 FK 被删除之前,这样您就可以访问这两个 FK 来迁移数据:# Generated by Django 3.1 on 2020-08-25 13:11from django.db import migrations, modelsdef migrate_office_to_profile(apps, schema_editor):    User = apps.get_model('so', 'User')    for user in User.objects.all():        for office in user.office_set:            user.profile.add(office)def migrate_office_to_user(apps, schema_editor):    Profile = apps.get_model('so', 'Profile')    for profile in Profile.objects.all():        profile.user.add(profile.offices)        for office in profile.office_set:            profile.user.add(office)class Migration(migrations.Migration):    dependencies = [        ('so', '0001_initial'),    ]    operations = [        migrations.AddField(            model_name='profile',            name='offices',            field=models.ManyToManyField(to='so.Office'),        ),        # This is where your python code will be called        migrations.RunPython(            # This is called in the forward migration            migrate_office_to_profile,            # This is called in the backward migration            reverse_code=migrate_office_to_user        ),        migrations.RemoveField(            model_name='user',            name='offices',        ),    ]我还没有在真实数据上测试过这个。这是你的部分。第 3 步:运行和调试您的迁移复制您的数据库,运行迁移并查看它是如何工作的:(.venv) ~/c/s/m/mysite> ./manage.py migrateOperations to perform:  Apply all migrations: admin, auth, contenttypes, sessions, soRunning migrations:  Applying so.0002_auto_20200825_1311... OK在处理数据迁移时,您应该始终编写和调试反向迁移:(.venv) ~/c/s/m/mysite> ./manage.py migrate so 0001Operations to perform:  Target specific migration: 0001_initial, from soRunning migrations:  Rendering model states... DONE  Unapplying so.0002_auto_20200825_1311... OK请记住,迁移文件被添加到版本控制和软件的一部分。===编辑===阐明反向或向后迁移的概念。您的 Django 迁移通常只以一种方式运行:增加迁移数量。但是对于您在开发过程中可能应用的所有测试和仔细思考,您不能总是考虑生产数据。代码很“简单”,因为它在生产中与在您的开发服务器上是一样的。但生产数据通常不同。在部署期间 Django 迁移可能会失败。例如,因为您正在添加一个您认为只能为真的显式唯一约束。但是不知何故,对于生产数据,迁移会引发完整性错误。然后,您将陷入半完成的迁移和没有迁移就无法运行的新代码。如果您花时间确保您的迁移可以前后运行而不会丢失数据,您可以安全地撤消迁移并恢复到以前的代码并返回以找出问题所在,而不必修复它当场。对于模型结构,前向和后向迁移由 Django 自动处理,但是对于数据迁移,您必须编写给migrations.RunPython.
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python