mysql - 无法使用 Django 3.0.3 中的迁移 API 使用 ModelState 和 ProjectState 进行迁移

标签 mysql django django-models migration django-migrations

我正在使用 ProjectState 迁移到表的新属性。我试图了解在 Django 3.0.3 中使用迁移 API 的 ModelState 和 ProjectState。

我无法迁移到具有新字段的新状态。有人可以帮助我 ProjectStateModelState使用什么来申请新的model_definition迁移工作?以下代码不会迁移到数据库,但不会给出任何错误。

我想从数据库表状态迁移到另一个状态并且有一些元数据_meta .

  • 当前数据库状态 model_state.fields是:

    [('id', <django.db.models.fields.AutoField>)]

  • future 的数据库状态model_state.fields添加 fields_attrs 后迁移应该是使用 models_definition :

    [('id', <django.db.models.fields.AutoField>), ('name', <django.db.models.fields.CharField>)]

模型定义代码是:

model_config 对象是

{
 '__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 = type(
                model_item.table_name,
                # TODO: Put this into Database
                # model_config.get("extends"),
                bases,
                model_config
            )

这是我使用的代码:

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()

我已阅读并使用 How to programmatically generate the CREATE TABLE SQL statement for a given model in Django?

欢迎就此提供任何帮助或资源。

更新:我确实尝试了 Django 的测试用例,但它无法以编程方式工作。我必须断然使用 addfield 吗?不确定如何让它工作。 projectstate 和 model_create 方式都不起作用

最佳答案

开始时,您需要使用模型元类,即。 <强> ModelBase ,而不是type:

from django.db.models.base import ModelBase

model_definition = ModelBase(
    model_item.table_name,
    bases,
    model_config
)

一旦您使用了正确的元类,您可能会收到无数错误,因为您正在使用 ModelBase 设置的许多类属性在内部,并不期望你自己设置。

您不应转储模型具有的所有属性,而应仅设置 ModelBase 希望在传统模型上设置的属性,其中包括:

  • __module____qualname__
  • 模型字段
  • 自定义管理器或查询集
  • 模型方法
  • 模型

应省略其他所有内容。

例如,如果您有一个看起来像这样的模型,在模块 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'

这些模型的动态版本需要如下所示:

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'}),
})

我不明白你的迁移代码的目的,所以我会假设这是一个试图让动态模型工作的黑客,这意味着你可以完全抛弃它并使用内置的迁移加载器,即:

python3 manage.py makemigrations myapp && python3 manage.py migrate myapp

我不熟悉python metaclasses ,我建议您仔细阅读它们,因为这是理解我的代码的先决条件。

关于mysql - 无法使用 Django 3.0.3 中的迁移 API 使用 ModelState 和 ProjectState 进行迁移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64639768/

相关文章:

php - 即使有更多数据要遍历数组元素也会中断循环

php - PHP : got nothing with printing the array 中的 SQL 查询

MySQL 将行转换为动态列数

javascript - 从 casperjs 测试脚本访问 ckeditor

python - 如何验证 django 自定义模型字段属性?

django - 将自定义属性添加到 django 模型字段

mysql - 在 `code` 之前更改表添加...?

mysql - Django 不显示来自数据库的更新数据

Django - 模板标签中的 verbose_name

python - 使用OIL自动旋转手机和加速度计拍摄的照片