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

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

问题描述

这是这个问题的扩展:如何在两个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屋!

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