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

Python 在保留数据的同时将Django外键移动到另一个模型?,python,django,Python,Django,我有一个Django应用程序,其中有一个基本的用户模型和用户配置文件模型 班级办公室(models.Model): name=models.CharField() 类用户(models.Model): email=models.EmailField() 办公室=模型。多个多个字段(办公室) 类配置文件(models.Model): 用户=模型。OneToOneField(用户) 每个用户都有一个配置文件,可以分配到许多不同的办公室 我想做的是拥有它,这样一个用户可以有许多配置文件,但配置文件可

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

班级办公室(models.Model):
name=models.CharField()
类用户(models.Model):
email=models.EmailField()
办公室=模型。多个多个字段(办公室)
类配置文件(models.Model):
用户=模型。OneToOneField(用户)
每个用户都有一个配置文件,可以分配到许多不同的办公室

我想做的是拥有它,这样一个用户可以有许多配置文件,但配置文件可以分配到不同的办公室

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

  • 找到一些方法将
    offices
    字段移到Profile字段

  • 按照
    ProfileNoUser
    的思路创建一个新的模型,该模型具有用户模型的外键,并且具有
    offices
    外键

  • 你认为哪种选择最好?如果#1,我该怎么做?

    你的问题是关于什么的

    如果是这样,您应该阅读链接文档

    我认为你的第一个建议确实是最好的

    下面是如何做到这一点

    步骤1:对模型进行更改 您可以更改模型以匹配目标:

    #models.py
    从django.db导入模型
    班级办公室(models.Model):
    name=models.CharField(最大长度=1000)
    类用户(models.Model):
    email=models.EmailField()
    类配置文件(models.Model):
    user=models.OneToOneField(用户,on_delete=models.CASCADE)
    办公室=模型。多个多个字段(办公室)
    
    运行
    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:编辑迁移文件以迁移现有数据 打开上一步创建的文件。它将看起来像:

    #由Django 3.1于2020-08-25 13:11生成
    从django.db导入迁移、模型
    类迁移(migrations.Migration):
    依赖项=[
    (‘so’、‘0001_首字母’),
    ]
    操作=[
    migrations.RemoveField(
    型号_name='user',
    办公室名称,
    ),
    migrations.AddField(
    型号_name='profile',
    办公室名称,
    field=models.ManyToManyField(to='so.Office'),
    ),
    ]
    
    在这里,您需要做两件事:

    • 您可以看到,对于Django生成的订单,它将首先删除旧的FK,然后添加新的FK。你应该改变这一点,让它成为另一种方式
    • 然后,您必须编写一些python代码,以便在正确的时间执行迁移
    正确的时间是在创建新FK之后和删除旧FK之前,这样您就可以访问这两个FK来迁移数据:

    #由Django 3.1于2020-08-25 13:11生成
    从django.db导入迁移、模型
    def将办公室迁移到配置文件(应用程序、架构编辑器):
    User=apps.get_model('so','User'))
    对于user.objects.all()中的用户:
    对于user.office\u集合中的office:
    user.profile.add(办公室)
    def将办公室迁移到用户(应用程序、架构编辑器):
    Profile=apps.get_model('so','Profile'))
    对于profile.objects.all()中的概要文件:
    profile.user.add(profile.offices)
    对于profile.office\u集合中的office:
    profile.user.add(办公室)
    类迁移(migrations.Migration):
    依赖项=[
    (‘so’、‘0001_首字母’),
    ]
    操作=[
    migrations.AddField(
    型号_name='profile',
    办公室名称,
    field=models.ManyToManyField(to='so.Office'),
    ),
    #这就是调用python代码的地方
    migrations.RunPython(
    #这称为正向迁移
    将办公室迁移到配置文件,
    #这称为向后迁移
    反向代码=将办公室迁移到用户
    ),
    migrations.RemoveField(
    型号_name='user',
    办公室名称,
    ),
    ]
    
    我还没有在真实数据上测试过这一点。这是你的职责。

    步骤3:运行并调试迁移 制作数据库的副本,运行迁移,并查看迁移过程:

    (.venv) ~/c/s/m/mysite> ./manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, sessions, so
    Running migrations:
      Applying so.0002_auto_20200825_1311... OK
    
    处理数据迁移时,应始终编写并调试反向迁移:

    (.venv) ~/c/s/m/mysite> ./manage.py migrate so 0001
    Operations to perform:
      Target specific migration: 0001_initial, from so
    Running migrations:
      Rendering model states... DONE
      Unapplying so.0002_auto_20200825_1311... OK
    
    请记住,迁移文件已添加到版本控制中,并且是软件的一部分

    ==编辑===

    阐明反向或反向迁移的概念

    Django迁移通常只以一种方式运行:增加迁移数量

    但是,尽管在开发过程中可能会进行各种测试和仔细思考,但您不能总是考虑生产数据。代码“简单”,因为它在生产环境中与在开发服务器上的代码相同。但生产数据通常是不同的

    Django迁移在部署期间可能会失败。例如,因为您正在添加一个您认为只能为真的显式唯一约束。但不知何故,对于生产数据,迁移将导致完整性错误

    然后,您将被困在完成了一半的迁移和没有迁移就无法运行的新代码中。如果您花时间确保迁移可以向前运行和向后运行而不丢失数据,则可以安全地撤消迁移并恢复到以前的代码,然后返回以找出错误所在,而不必当场修复


    Django会自动为模型结构处理向前和向后迁移,但对于数据迁移,您必须编写为
    迁移提供的函数。运行Python

    ,以便
    用户可以为每个
    办公室
    创建一个
    配置文件?因此,它是m2m关系A中的“中间”表