gpt4 book ai didi

python - 将 django 模型移动到另一个应用程序,该应用程序是另一个模型的父模型

转载 作者:行者123 更新时间:2023-12-01 01:21:23 24 4
gpt4 key购买 nike

我必须在两个不同的应用程序(例如app1和app2)中建立django模型,在app1中我得到了Model1,在app2中我得到了BaseModel,Model1是这样的

class Model1(BaseModel):
...

Model1 和 BaseModel 在一个应用程序中,但我将 Model1 移至 app2,现在我也想将 BaseModel 移至 app2。我的问题是当我尝试将 BaseModel 移动到 app2 时出现此错误:

Cannot resolve bases for [<ModelState: 'app1.model1'>]
This can happen if you are inheriting models from an app with migrations (e.g. contrib.auth)
in an app with no migrations; see https://docs.djangoproject.com/en/2.1/topics/migrations/#dependencies for more

我所做的很简单:

  1. 我编写迁移以将 BaseModel 的表重命名为 app2_basemodel,然后编写迁移以在 app2 中创建模型
  2. 我创建迁移来更改用于继承的字段basemodel_ptr
  3. 我将 BaseModel 代码移至 app2,并通过从 app1 迁移来删除 BaseModel

此方法适用于移动 Model1,但当我尝试移动此基本模型时,出现此错误。

我感谢任何帮助,包括任何其他方式来实现将 BaseModel 移动到 app1 的重构想法

最佳答案

Django 没有为此提供内置的迁移操作,但您可以通过组合多个迁移操作来实现此目的。

迁移不仅会更改数据库,还会保留所有模型的状态。您必须确保状态与数据库保持同步,这使事情变得有点复杂。关键是使用migrations.SeparateDatabaseAndState .

假设您有这些模型定义:

# app1/models.py
from django.db import models

class BaseModel(models.Model):
base_field = models.CharField(max_length=64)

# app2/models.py
from django.db import models
from app1.models import BaseModel

class Model1(BaseModel):
model_field = models.CharField(max_length=64)

并且您想迁移到此:

# app1/models.py empty
# app2/models.py

from django.db import models

class BaseModel(models.Model):
base_field = models.CharField(max_length=64)

class Model1(BaseModel):
model_field = models.CharField(max_length=64)

您必须创建三个迁移:

  • 在 App1 中:将 app1.BaseModel 表从 app1_basemodel 重命名为 app2_basemodel。这还负责调整 basemodel_ptr 列上的外键约束。
  • 在 App2 中:添加 app2.BaseModel 并使用 app2.BaseModel 作为基础模型重新创建 app2.Model1。这些更改仅针对迁移状态进行,不会触及数据库!
  • 在 App1 中:从迁移状态中删除 app1.BaseModel。同样,数据库没有变化。

代码如下:

# app1/migrations/0002_rename_basemodel_table.py
from django.db import migrations, models


class Migration(migrations.Migration):
atomic = False
dependencies = [
('app1', '0001_initial'),
]
operations = [
migrations.AlterModelTable(
name='BaseModel',
table='app2_basemodel'
),
]

# app2/migrations/0002_change_basemodel.py
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('app2', '0001_initial'),
('app1', '0002_rename_basemodel_table')
]

state_operations = [
migrations.CreateModel(
name='BaseModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('base_field', models.CharField(max_length=64)),
],
),
migrations.DeleteModel(
name='Model1',
),
migrations.CreateModel(
name='Model1',
fields=[
('basemodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='app2.BaseModel')),
],
bases=('app2.basemodel',),
),
]
database_operations = [
]
operations = [
migrations.SeparateDatabaseAndState(
database_operations,
state_operations
)
]

# app1/0003_remove_basemodel.py
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('app1', '0002_rename_basemodel_table'),
('app2', '0002_change_basemodel')
]

state_operations = [
migrations.DeleteModel(
name='BaseModel',
),
]
operations = [
migrations.SeparateDatabaseAndState(
database_operations=None,
state_operations=state_operations
)
]

显然,您必须调整这些迁移以反射(reflect)您的实际模型。恐怕如果您有其他与 Model1 相关的模型,这可能会变得更加复杂。

免责声明:我已经使用 SQLite 和 PostgreSQL 测试了这些,但使用它的风险由您自行承担!在对生产数据运行之前,请确保您有备份。

之前:

$ python manage.py dbshell
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
CREATE TABLE IF NOT EXISTS "app1_basemodel" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "base_field" varchar(64) NOT NULL);
CREATE TABLE IF NOT EXISTS "app2_model1" ("basemodel_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "app1_basemodel" ("id") DEFERRABLE INITIALLY DEFERRED, "model_field" varchar(64) NOT NULL);
...

$ python manage.py shell
Python 3.7.0 (default, Aug 22 2018, 15:22:33)
[Clang 9.1.0 (clang-902.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from app2.models import Model1
>>> Model1.__bases__
(<class 'app1.models.BaseModel'>,)
>>> Model1.objects.create(base_field='a', model_field='A')
<Model1: Model1 object (1)>
>>> Model1.objects.create(base_field='b', model_field='B')
<Model1: Model1 object (2)>
>>>

之后:

sqlite> .schema
...
CREATE TABLE IF NOT EXISTS "app2_basemodel" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "base_field" varchar(64) NOT NULL);
CREATE TABLE IF NOT EXISTS "app2_model1" ("basemodel_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "app2_basemodel" ("id") DEFERRABLE INITIALLY DEFERRED, "model_field" varchar(64) NOT NULL);
...

>>> from app2.models import Model1
>>> Model1.__bases__
(<class 'app2.models.BaseModel'>,)
>>> for obj in Model1.objects.all():
... print(obj.base_field, obj.model_field)
...
a A
b B

或者,您可以查看 writing a custom migration operation .

关于python - 将 django 模型移动到另一个应用程序,该应用程序是另一个模型的父模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53802842/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com