问题描述
我正在使用 ProjectState 迁移到表的新属性.我正在尝试了解在 Django 3.0.3 中使用迁移 API 的 ModelState 和 ProjectState.
I am using ProjectState to migrate to a new attributes of a table. I am trying to understand the ModelState and ProjectState using of migrations API in Django 3.0.3.
我无法迁移到具有新字段的新州.有人可以帮助我了解 ProjectState
和 ModelState
使用什么来申请新的 model_definition 迁移工作吗?以下代码不会迁移到数据库,但不会出现任何错误.
I am unable to migrate to the new state which has new fields. Can someone help me with the ProjectState
and ModelState
usage of what to apply for new model_definition migration to work? The following code does not migrate to DB but doesnt give any error.
我想从一个数据库表状态迁移到另一个状态,并且有一些元数据_meta
.
I want to migrate from a DB table state to another state and there are some metadata _meta
.
当前数据库状态
model_state.fields
为:
[('id', <django.db.models.fields.AutoField>)]
添加 fields_attrs
迁移后的未来数据库状态 model_state.fields
应该是使用 models_definition
的:
The future DB state model_state.fields
after adding fields_attrs
migrations should be this using the models_definition
:
[('id', <django.db.models.fields.AutoField>), ('name', <django.db.models.fields.CharField>)]
模型定义代码为:
model_config 对象是
model_config object is
{
'__module__': 'testmodule', 'app_label': 'testmodule',
'__unicode__': <function ModelScript.model_create_config.<locals>.<lambda> at 0x00000221B6FBEF70>,
'attrs': {'name': <django.db.models.fields.CharField>}
}
model_definition 是:
model_definition is:
model_definition = type(
model_item.table_name,
# TODO: Put this into Database
# model_config.get("extends"),
bases,
model_config
)
这是我正在使用的代码:
This is the code I am using:
from django.db.migrations.state import ProjectState
from django.db.migrations.migration import Migration
from django.db.migrations.state import ModelState
from django.db.migrations import operations
# model_definition is coming from a function as the following object
model_definition = {'__module__': 'testmodule', 'app_label': 'testmodule', '__unicode__': <function ModelScript.model_create_config.<locals>.<lambda> at 0x000002047275FF70>, 'attrs': {'name': <django.db.models.fields.CharField>}, '__doc__': 'SampleModel(id)', '_meta': <Options for SampleModel>, 'DoesNotExist': <class 'testmodule.SampleModel.DoesNotExist'>, 'MultipleObjectsReturned': <class 'testmodule.SampleModel.MultipleObjectsReturned'>, 'id': <django.db.models.query_utils.DeferredAttribute object at 0x00000204727F9430>, 'objects': <django.db.models.manager.ManagerDescriptor object at 0x00000204727F9490>}
model_state = ModelState.from_model(model_definition)
# field_attrs are all the new fields to be migrated
for k,v in field_attrs.items():
model_state.fields.append((k, v))
# Create a fake migration with the CreateModel operation
cm = operations.CreateModel(name=model_state.name, fields=model_state.fields)
migration = Migration("fake_migration", model_state.app_label)
migration.operations.append(cm)
# SHOULD ProjectState be used for the new definition to be APPLIED to DB and HOW?
state = ProjectState()
with db_conn.schema_editor(collect_sql=True, atomic=migration.atomic) as schema_editor:
# Following create_model also doesnot migrate to Mysql DB
# Gives a Table exists Error even with root user of mysql
# schema_editor.create_model(model_definition)
# Following doesnot migrate to the new required state
state = migration.apply(state, schema_editor, collect_sql=True)
# Following gives atomic transaction error if used along with atomic
# following commit commented gives no error but doesnt migrate
# db_conn.commit()
我已阅读此内容并使用 如何在 Django 中以编程方式为给定模型生成 CREATE TABLE SQL 语句?
I have read this and using How to programmatically generate the CREATE TABLE SQL statement for a given model in Django?
欢迎任何帮助或资源.
更新:我确实尝试了 Django 的测试用例,但它不能以编程方式工作.我必须明确使用 addfield 吗?不确定如何让这个工作.projectstate 和 model_create 方式都不起作用
Update: I did try the test cases of Django and it didn't work programmatically. Do I have to use addfield categorically? Unsure of how to get this working. Both projectstate and model_create way is not working
推荐答案
首先,您需要使用模型元类,即.ModelBase
,而不是 type
:
To start, you need to be using the model metaclass, ie. ModelBase
, and not type
:
from django.db.models.base import ModelBase
model_definition = ModelBase(
model_item.table_name,
bases,
model_config
)
一旦你使用了正确的metaclass,你可能会收到无数的错误,因为你使用了很多ModelBase
设置的类属性内部,并不指望你设置自己.
Once you use the proper metaclass, you will likely receive a myriad of errors, since you are using many class attributes that ModelBase
sets internally, and is not expecting you to set yourself.
您应该只设置 ModelBase
期望在传统模型上设置的属性,而不是转储模型具有的所有属性,其中包括:
Instead of dumping all the attributes that your model has, you should only set the attributes that ModelBase
expects to be set on a traditional model, which includes:
__module__
和__qualname__
- 模型字段
- 自定义管理器或查询集
- 模型方法
- 模型
元
其他的都应该省略.
例如,如果您有一个看起来像这样的模型,在模块 myapp.models
中:
So for example, if you have a models that look like this, in the module myapp.models
:
class Parent(models.Model):
name = models.CharField(max_length=45)
class Child(models.Model):
name = models.CharField(max_length=45)
parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
class ModelWithMeta(models.Model):
class Meta:
db_table = 'some_table'
这些模型的动态版本需要如下所示:
The dynamic version of these models need to look like this:
from django.db import models
from django.db.models.base import ModelBase
bases = (models.Model,)
Parent = ModelBase('Parent', bases, {
'__module__': 'myapp.models',
'__qualname__': 'Parent',
'name': models.CharField(max_length=45),
})
Child = ModelBase('Child', bases, {
'__module__': 'myapp.models',
'__qualname__': 'Child',
'name': models.CharField(max_length=45),
'parent': models.ForeignKey('myapp.Parent', on_delete=models.CASCADE),
})
ModelWithMeta = ModelBase('ModelWithMeta', bases, {
'__module__': 'myapp.models',
'__qualname__': 'ModelWithMeta',
'Meta': type('Meta', (), {'db_table': 'some_table'}),
})
我不明白你的迁移代码的目的,所以我会假设这是一个试图让动态模型工作的黑客,这意味着你可以完全扔掉它并使用内置的迁移加载器,即:
I don't understand the purpose of your migration code, so I will assume that it was a hack in attempt to get the dynamic models working, which means you can probably throw it out altogether and use the builtin migration loader, ie:
python3 manage.py makemigrations myapp && python3 manage.py migrate myapp
我你不熟悉 python 元类
,我建议阅读它们,因为这是理解我的代码的先决条件.
I you aren't familiar with python metaclasses
, I'd recommend reading up on them, since it's a prerequisite to understand my code.
这篇关于无法使用 Django 3.0.3 中的迁移 API 使用 ModelState 和 ProjectState 进行迁移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!