无法使用Django 3.0.3中的Migrations API使用ModelState和ProjectState进行迁移 [英] Unable to migrate using ModelState and ProjectState using of migrations API in Django 3.0.3

查看:44
本文介绍了无法使用Django 3.0.3中的Migrations API使用ModelState和ProjectState进行迁移的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用ProjectState迁移到表的新属性.我正在尝试使用Django 3.0.3.中的migrations API来了解ModelState和ProjectState.

我无法迁移到具有新字段的新状态.有人可以帮助我使用 ProjectState ModelState 的用法来申请新的model_definition迁移吗?以下代码不会迁移到数据库,但不会出现任何错误.

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

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

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

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

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

模型定义代码为:

model_config对象是

  {'__module__':'testmodule','app_label':'testmodule','__unicode __':<函数ModelScript.model_create_config.< locals>.< lambda>在0x00000221B6FBEF70> ;,'attrs':{'name':< django.db.models.fields.CharField>}} 

model_definition是:

  model_definition = type(model_item.table_name,#TODO:将此放入数据库#model_config.get("extends"),基地,model_config) 

这是我正在使用的代码:

从django.db.migrations.state中的

 导入ProjectState从django.db.migrations.migration导入迁移从django.db.migrations.state导入ModelState从django.db.migrations导入操作#model_definition来自作为以下对象的函数model_definition = {'__module__':'testmodule','app_label':'testmodule','__unicode__':<功能ModelScript.model_create_config.< locals>.< lambda>at 0x000002047275FF70> ;,'attrs':{'name':< django.db.models.fields.CharField>},'__doc__':'SampleModel(id)','_meta':< SampleModel的选项> ;,'AresNotExist':< class'testmodule.SampleModel.DoesNotExist'> ;,'MultipleObjectsReturned':<类'testmodule.SampleModel.MultipleObjectsReturned'> ;,'id':< django.db.models.query_utils.DeferredAttribute对象位于0x00000204727F9430> ;,对象":< django.db.models.manager.ManagerDescriptor对象位于0x00000204727F9490>}model_state = ModelState.from_model(model_definition)#field_attrs是所有要迁移的新字段对于field_attrs.items()中的k,v:model_state.fields.append((k,v))#使用CreateModel操作创建假迁移cm = Operations.CreateModel(名称= model_state.name,字段= model_state.fields)迁移=迁移("fake_migration",model_state.app_label)migration.operations.append(cm)#应该将ProjectState用于要应用于DB和HOW的新定义吗?状态= ProjectState()使用db_conn.schema_editor(collect_sql = True,atomic = migration.atomic)作为schema_editor:#跟随create_model也不会迁移到Mysql DB#给出一个表存在错误,即使是mysql的root用户#schema_editor.create_model(model_definition)#以下内容不会迁移到新的必需状态状态= migration.apply(状态,schema_editor,collect_sql = True)#如果与atomic一起使用,以下给出atomic事务错误#在提交注释后没有错误但不会迁移#db_conn.commit() 

我已阅读并使用解决方案

首先,您需要使用模型元类,即. ModelBase ,而不是 类型 :

从django.db.models.base导入

 model_definition = ModelBase(model_item.table_name,基地,model_config) 

一旦使用了正确的 metaclass ,由于使用的是 ModelBase 设置的许多类属性,您可能会收到无数的错误.内部的,并且不希望您自己动手.

除了转储模型具有的所有属性外,您应该只设置 ModelBase 期望在传统模型上设置的属性,其中包括:

  • __ module __ __ qualname __
  • 模型字段
  • 客户经理或查询集
  • 模型方法
  • 模型

其他所有内容都应省略.

例如,如果您有一个看起来像这样的模型,请在模块 myapp.models 中:

  class Parent(models.Model):名称= models.CharField(max_length = 45)Child(models.Model)类:名称= models.CharField(max_length = 45)父=模型.ForeignKey(父母,on_delete =模型.CASCADE)ModelWithMeta(models.Model)类:类Meta:db_table ='some_table' 

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

django.db导入模型中的

 从django.db.models.base导入ModelBase基数=(models.Model,)Parent = ModelBase('Parent',bases,{'__module__':'myapp.models','__qualname__':'父母','名称':models.CharField(max_length = 45),})Child = ModelBase('Child',bases,{'__module__':'myapp.models','__qualname__':'孩子','名称':models.CharField(max_length = 45),'父母':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迁移myapp 

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

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.

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.

I want to migrate from a DB table state to another state and there are some metadata _meta.

  • The current DB state model_state.fields is:

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

  • 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 Definition Code is:

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

I have read this and using How to programmatically generate the CREATE TABLE SQL statement for a given model in Django?

Any help or resource is welcome on this.

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

解决方案

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
)

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.

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__ and __qualname__
  • model fields
  • custom managers or querysets
  • model methods
  • model Meta

Everything else should be omitted.

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

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中的Migrations API使用ModelState和ProjectState进行迁移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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