在具有所需外键引用的 Django (1.8) 应用程序之间移动模型 [英] Move models between Django (1.8) apps with required ForeignKey references

查看:25
本文介绍了在具有所需外键引用的 Django (1.8) 应用程序之间移动模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是这个问题的扩展:如何在两个 Django 应用程序 (Django 1.7) 之间移动模型

我需要将一堆模型从 old_app 移动到 new_app.最好的答案似乎是 Ozan 的,但是由于需要外键引用,事情有点棘手.@halfnibble 在对 Ozan 的回答的评论中提供了一个解决方案,但我仍然无法确定步骤的精确顺序(例如,我何时将模型复制到 new_app,何时删除模型来自 old_app,哪些迁移将位于 old_app.migrationsnew_app.migrations 等中)

I need to move a bunch of models from old_app to new_app. The best answer seems to be Ozan's, but with required foreign key references, things are bit trickier. @halfnibble presents a solution in the comments to Ozan's answer, but I'm still having trouble with the precise order of steps (e.g. when do I copy the models over to new_app, when do I delete the models from old_app, which migrations will sit in old_app.migrations vs. new_app.migrations, etc.)

非常感谢任何帮助!

推荐答案

在应用之间迁移模型.

简短的回答是,不要这样做!!

但是这个答案很少适用于实际项目和生产数据库的现实世界.因此,我创建了一个示例 GitHub 存储库 来演示这个相当复杂的过程.

But that answer rarely works in the real world of living projects and production databases. Therefore, I have created a sample GitHub repo to demonstrate this rather complicated process.

我正在使用 MySQL.(不,那些不是我的真实凭据).

I am using MySQL. (No, those aren't my real credentials).

问题

我使用的示例是带有 cars 应用的工厂项目,该应用最初具有 Car 模型和 Tires 模型.

The example I'm using is a factory project with a cars app that initially has a Car model and a Tires model.

factory
  |_ cars
    |_ Car
    |_ Tires

Car 模型与 Tires 有外键关系.(如,您通过汽车模型指定轮胎).

The Car model has a ForeignKey relationship with Tires. (As in, you specify the tires via the car model).

然而,我们很快意识到Tires 将是一个拥有自己的视图等的大型模型,因此我们希望在自己的应用程序中使用它.因此,所需的结构是:

However, we soon realize that Tires is going to be a large model with its own views, etc., and therefore we want it in its own app. The desired structure is therefore:

factory
  |_ cars
    |_ Car
  |_ tires
    |_ Tires

而且我们需要保持CarTires之间的ForeignKey关系,因为太多依赖于保存数据.

And we need to keep the ForeignKey relationship between Car and Tires because too much depends on preserving the data.

解决方案

第 1 步.使用糟糕的设计设置初始应用.

Step 1. Setup initial app with bad design.

浏览第1步的代码.

第 2 步. 创建一个管理界面并添加一堆包含外键关系的数据.

Step 2. Create an admin interface and add a bunch of data containing ForeignKey relationships.

查看第 2 步

第 3 步. 决定将 Tires 模型移动到它自己的应用中.小心翼翼地将代码剪切并粘贴到新的轮胎应用程序中.确保更新 Car 模型以指向新的 tires.Tires 模型.

Step 3. Decide to move the Tires model to its own app. Meticulously cut and paste code into the new tires app. Make sure you update the Car model to point to the new tires.Tires model.

然后运行 ​​./manage.py makemigrations 并在某处备份数据库(以防万一失败).

Then run ./manage.py makemigrations and backup the database somewhere (just in case this fails horribly).

最后运行./manage.py migrate,看到doom的错误信息,

Finally, run ./manage.py migrate and see the error message of doom,

django.db.utils.IntegrityError: (1217, '无法删除或更新父行:外键约束失败')

第 3 步中查看代码和迁移.

第 4 步. 棘手的部分.自动生成的迁移无法看到您只是将模型复制到不同的应用程序.所以,我们必须做一些事情来解决这个问题.

Step 4. The tricky part. The auto-generated migration fails to see that you've merely copied a model to a different app. So, we have to do some things to remedy this.

您可以在第 4 步中查看带有注释的最终迁移.确实对此进行了测试以验证它是否有效.

You can follow along and view the final migrations with comments in step 4. I did test this to verify it works.

首先,我们将研究汽车.您必须进行新的空迁移.此迁移实际上需要在最近创建的迁移(未能执行的迁移)之前运行.因此,我重新编号了我创建的迁移并更改了依赖项以首先运行我的自定义迁移,然后是 cars 应用程序的最后一个自动生成的迁移.

First, we are going to work on cars. You have to make a new, empty migration. This migration actually needs to run before the most recently created migration (the one that failed to execute). Therefore, I renumbered the migration I created and changed the dependencies to run my custom migration first and then the last auto-generated migration for the cars app.

您可以使用以下命令创建空迁移:

You can create an empty migration with:

./manage.py makemigrations --empty cars

步骤 4.a. 进行自定义 old_app 迁移.

Step 4.a. Make custom old_app migration.

在第一次自定义迁移中,我将只执行database_operations"迁移.Django 为您提供了拆分状态"和数据库"操作的选项.您可以通过查看代码.

In this first custom migration, I'm only going to perform a "database_operations" migration. Django gives you the option to split "state" and "database" operations. You can see how this is done by viewing the code here.

我在第一步中的目标是将数据库表从 oldapp_model 重命名为 newapp_model 而不影响 Django 的状态.您必须根据应用程序名称和模型名称弄清楚 Django 会如何命名您的数据库表.

My goal in this first step is to rename the database tables from oldapp_model to newapp_model without messing with Django's state. You have to figure out what Django would have named your database table based on the app name and model name.

现在您已准备好修改初始tires 迁移.

Now you are ready to modify the initial tires migration.

步骤 4.b. 修改 new_app 初始迁移

操作没问题,但我们只想修改状态"而不是数据库.为什么?因为我们保留了 cars 应用程序中的数据库表.此外,您需要确保之前进行的自定义迁移是此迁移的依赖项.查看轮胎迁移文件.

The operations are fine, but we only want to modify the "state" and not the database. Why? Because we are keeping the database tables from the cars app. Also, you need to make sure that the previously made custom migration is a dependency of this migration. See the tires migration file.

所以,现在我们在数据库中将cars.Tires重命名为tires.Tires,并更改Django状态以识别tires.Tires表.

So, now we have renamed cars.Tires to tires.Tires in the database, and changed the Django state to recognize the tires.Tires table.

步骤 4.c. 修改 old_app 上次自动生成的迁移.

Step 4.c. Modify old_app last auto-generated migration.

回到汽车,我们需要修改上次自动生成的迁移.它应该需要我们的第一次定制汽车迁移,以及最初的轮胎迁移(我们刚刚修改过).

Going back to cars, we need to modify that last auto-generated migration. It should require our first custom cars migration, and the initial tires migration (that we just modified).

这里我们应该保留 AlterField 操作,因为 Car 模型指向到一个不同的模型(即使它有相同的数据).但是,我们需要删除有关DeleteModel 的迁移行,因为cars.Tires 模型不再存在.它已完全转换为tires.Tires.查看此迁移.

Here we should leave the AlterField operations because the Car model is pointing to a different model (even though it has the same data). However, we need to remove the lines of migration concerning DeleteModel because the cars.Tires model no longer exists. It has fully converted into tires.Tires. View this migration.

步骤 4.d. 清理 old_app 中的陈旧模型.

Step 4.d. Clean up stale model in old_app.

最后但并非最不重要的一点是,您需要在汽车应用中进行最终的自定义迁移.在这里,我们将做一个状态"操作,只是为了删除 cars.Tires 模型.它是状态唯一的,因为 cars.Tires 的数据库表已经被重命名.此最后一次迁移清理了剩余的 Django 状态.

Last but not least, you need to make a final custom migration in the cars app. Here, we will do a "state" operation only to delete the cars.Tires model. It is state-only because the database table for cars.Tires has already been renamed. This last migration cleans up the remaining Django state.

这篇关于在具有所需外键引用的 Django (1.8) 应用程序之间移动模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆