在Django(1.8)应用程序之间移动模型,并使用所需的ForeignKey引用 [英] Move models between Django (1.8) apps with required ForeignKey references
问题描述
这是这个问题的扩展:如何在两个Django应用程序之间移动模型(Django 1.7)
我需要从 old_app
to new_app
。最好的答案似乎是 Ozan的,但是要求外键引用,事情有点棘手。 @halfnibble在Ozan答案的评论中提出了一个解决方案,但是我仍然遇到精确的步骤顺序问题(例如,什么时候将模型复制到 new_app
何时从 old_app
中删除模型,哪些迁移将位于 old_app.migrations
与 new_app.migrations
等)
任何帮助非常感谢!
在应用之间迁移模型
简单的答案是,不要这样做!!
但是,答案很少在生活项目的现实世界中起作用,生产数据库。因此,我已经创建了一个示例GitHub repo 来演示这个相当复杂的过程。
我正在使用MySQL。
问题
我使用的示例是一个带有 cars 应用程序的工厂项目,最初有一个 Car
模型, 轮胎
型号。
工厂
| _汽车
| _汽车
| _轮胎
Car
model与Foreign $ C>轮胎。 (如同,您通过汽车型号指定轮胎)。
然而,我们很快就意识到,轮胎
将是一个拥有自己的意见等的大型模型,因此我们希望它在自己的应用程序。因此,所需的结构是:
工厂
| _汽车
| _汽车
| _轮胎
| _轮胎
我们需要保持ForeignKey关系 Car
和轮胎
,因为太多取决于保留数据。
解决方案
步骤1。设置设计不良的初始应用程序。
浏览第1步的代码。
步骤2。创建管理界面并添加一堆包含ForeignKey关系的数据。
查看步骤2.
步骤3。决定将轮胎
模型移动到自己的应用程序。仔细地将代码剪切并粘贴到新的轮胎应用程序中。确保您更新 Car
模型以指向新的 tire.Tires
模型。
然后运行 ./ manage.py makemigrations
并在某个地方备份数据库(以防万一这可怕)。
最后,运行 ./ manage.py migrate
,看到doom的错误信息,
django.db.utils.IntegrityError:(1217,无法删除或更新父行:外键约束失败)
查看到目前为止在步骤3. 中的代码和迁移
步骤4。棘手的部分。自动生成的迁移无法看到您只将模型复制到其他应用程序。所以,我们必须做一些事情来补救这个问题。
您可以跟随并查看最终的迁移,并在步骤4. 我做了测试,以验证它的工作原理。
首先,我们将在车上工作
。你必须做一个新的,空的迁移。这种迁移实际上需要在最近创建的迁移(无法执行的迁移)之前运行。因此,我重新编号了我创建的迁移,并更改了依赖关系以首先运行我的自定义迁移,然后重新编写汽车应用程序的最后一个自动生成的迁移。
您可以创建一个空的迁移:
./ manage.py makemigrations --empty汽车
步骤4.a。自定义 old_app migration。
在第一次自定义迁移中,我只会执行database_operations迁移。 Django为您提供拆分状态和数据库操作的选项。您可以查看此处的代码。
我第一步的目标是将数据库表从 oldapp_model
重命名为 newapp_model
而不会搞砸Django的状态。你必须弄清楚Django会根据应用程序名称和型号命名数据库表。
现在您可以修改初始的轮胎
迁移。
步骤4.b。修改 new_app 初始迁移
操作正常,但我们只想修改状态而不是数据库。为什么?因为我们正在保留来自的数据库表
应用程序。此外,您需要确保以前进行的自定义迁移是此迁移的依赖关系。请参阅轮胎迁移文件。
所以,现在我们已经将 cars.Tires
重命名为 tires.Tires
数据库,并更改Django状态以识别 tires.Tires
表。
步骤4.c。修改 old_app 最后自动生成的迁移。
将回到到汽车,我们需要修改最后一次自动生成的迁移。它应该需要我们的第一个定制汽车迁移和初始轮胎迁移(我们刚刚修改)。
这里我们应该离开 AlterField
操作,因为 Car
模型正在将指向不同的模型(即使它具有相同的数据)。但是,由于 cars.Tires
模型不再存在,因此我们需要删除有关 DeleteModel
的迁移行。它已经完全转换为 tire.Tires
。查看此迁移。
步骤4.d。清理 old_app 中的陈旧模型。
但同样重要的是,您需要在汽车应用程序中进行最终自定义迁移。在这里,我们将进行状态操作,只能删除 cars.Tires
模型。它是状态的,因为 cars.Tires
的数据库表已经被重命名。此上次迁移会清理剩余的Django状态。 / p>
This is an extension to this question: How to move a model between two Django apps (Django 1.7)
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.)
Any help is much appreciated!
Migrating a model between apps.
The short answer is, don't do it!!
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.
I am using MySQL. (No, those aren't my real credentials).
The Problem
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
The Car
model has a ForeignKey relationship with Tires
. (As in, you specify the tires via the car model).
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
And we need to keep the ForeignKey relationship between Car
and Tires
because too much depends on preserving the data.
The Solution
Step 1. Setup initial app with bad design.
Browse through the code of step 1.
Step 2. Create an admin interface and add a bunch of data containing ForeignKey relationships.
View step 2.
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.
Then run ./manage.py makemigrations
and backup the database somewhere (just in case this fails horribly).
Finally, run ./manage.py migrate
and see the error message of doom,
django.db.utils.IntegrityError: (1217, 'Cannot delete or update a parent row: a foreign key constraint fails')
View code and migrations so far in step 3.
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.
You can follow along and view the final migrations with comments in step 4. I did test this to verify it works.
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
Step 4.a. Make custom old_app migration.
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.
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.
Now you are ready to modify the initial tires
migration.
Step 4.b. Modify new_app initial migration
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.
So, now we have renamed cars.Tires
to tires.Tires
in the database, and changed the Django state to recognize the tires.Tires
table.
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).
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.
Step 4.d. Clean up stale model in old_app.
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)应用程序之间移动模型,并使用所需的ForeignKey引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!