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

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

问题描述

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



我需要移动一堆模型从 old_app new_app 。最好的答案似乎是 Ozan的,但是用所需的外键引用,事情有点棘手。 @halfnibble在对Ozan的回答的评论中提出了一个解决方案,但我仍然有困难的确切的步骤顺序(例如,当我复制模型到 new_app 何时从 old_app 中删除​​模型,这些迁移将位于 old_app.migrations new_app.migrations 等)



任何帮助都非常感谢!

解决方案

在应用程序之间迁移模型



简单的答案是,不要这样做。



但是这个答案很少适用于现实生活中的项目,生产数据库。因此,我创建了一个示例GitHub repo 来演示这个相当复杂的过程。



我使用MySQL。


$ b

b

我使用的示例是一个带有汽车应用程序的工厂项目,该应用程序最初有一个 Car 模型和轮胎模型。

  factory 
| _ cars
| _ Car
| _轮胎

Car 模型与轮胎。 (如,在通过汽车模型指定轮胎)。



但是,我们很快就会意识到 Tyres 会是一个拥有自己的视图等的大型模型,因此我们希望它在自己的应用程序。因此,所需的结构是:

  factory 
| _ car
| _ Car
| _ tires
| _轮胎

我们需要保持ForeignKey关系 Car 轮胎,因为太多取决于保存数据。



解决方案



步骤1。设置初始应用时设计不当。



浏览步骤1的代码。



步骤2。创建一个管理界面,并添加一堆包含ForeignKey关系的数据。



查看步骤2.



步骤3。决定将轮胎模型移动到自己的应用程式。仔细剪切和粘贴代码到新的轮胎应用程序。请务必更新 Car 模型,以指向新的 tires.Tires 模型。



然后运行 ./ manage.py makemigrations 并将数据库备份到某处(以免万一发生故障)。



最后,运行 ./ manage.py migrate 并查看doom的错误消息,



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



步骤3中查看代码和迁移功能。



步骤4。棘手的部分。自动生成的迁移无法看到您只是将模型复制到其他应用。



您可以在步骤4. 我测试了这个验证它的工作。



首先,我们将在 cars 上工作。你必须进行一个新的,空的迁移。此迁移实际上需要在最近创建的迁移(无法执行的迁移)之前运行。因此,我重新编号了我创建的迁移,并更改了依赖关系,以便先运行自定义迁移,然后为 cars 应用程序执行最后一次自动生成的迁移。



您可以使用以下方法创建空迁移:

  ./ manage.py makemigrations --empty汽车

步骤4.a。 em>迁移。



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



我的目标是将数据库表从 oldapp_model 重命名为 newapp_model ,而不会影响Django的状态。你必须弄清楚Django会根据应用程序名称和模型名称命名数据库表。



现在您可以修改初始轮胎迁移。



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



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



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



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



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



这里我们应该离开 AlterField 操作,因为 Car 模型指向不同的模型(即使它具有相同的数据)。但是,我们需要删除涉及 DeleteModel 的迁移行,因为 cars.Tires 模型不再存在。它已完全转换为 tires.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.

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

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