我正在尝试根据现有模型中的字段动态生成新模型。两者都在 /apps/main/models.py
中定义.现有模型如下所示:
from django.db import models
class People(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
height = models.IntegerField()
我有一个包含要复制的字段名称的列表:
target_fields = ["name", "age"]
我想生成一个新模型,该模型具有
target_fields
中命名的所有字段,但在这种情况下,它们应该被索引( db_index = True
)。我最初希望我能够迭代
People
的类属性。并使用 copy.copy
复制在其上定义的字段描述。像这样:from copy import copy
d = {}
for field_name in target_fields:
old_field = getattr(People, field_name) # alas, AttributeError
new_field = copy(old_field)
new_field.db_index = True
d[field_name] = new_field
IndexedPeople = type("IndexedPeople", (models.Model,), d)
我不确定是否
copy.copy()
ing Fields 可以工作,但我没有深入了解:类定义中列出的字段实际上并未作为类对象的属性包含在内。我假设它们被用于一些元类恶作剧。在调试器中摸索之后,我发现了一些列在
People._meta.local_fields
中的 Field 对象类型。 .然而,这些不仅仅是简单的描述,可以是 copy.copy()
ed 并用于描述另一个模型。例如,它们包括 .model
属性引用 People
.如何基于现有模型的字段为新模型创建字段描述?
最佳答案
从调试器和源代码中寻找:所有 Django 模型都使用 ModelBase
/db/models/base.py
中定义的元类.对于模型类定义中的每个字段,ModelBase
的 .add_to_class
方法将调用该字段的 .contribute_to_class
方法。Field.contribute_to_class
在 /db/models/fields/__init__.py
中定义它负责将字段定义与特定模型相关联。通过添加 .model
修改该字段属性并通过调用 .set_attributes_from_name
具有模型类定义中使用的名称的方法。这反过来又增加了 .attname
和 .column
属性和集 .name
和 .verbose_name
如有必要。
当我检查 __dict__
新定义的属性 CharField
并将其与 CharField
的比较已经与模型相关联,我还看到这些是唯一的区别:
.creation_counter
属性对于每个实例都是唯一的。 .attrname
, .column
和 .model
新实例上不存在属性。 .name
和 .verbose_name
属性是 None
在新实例上。 似乎无法区分
.name
/.verbose_name
手动指定给构造函数的属性和自动生成的属性。您需要选择始终重置它们,忽略任何手动指定的值,或者从不清除它们,这将导致它们始终忽略在新模型中给定的任何新名称。我想使用与原始字段相同的名称,所以我不打算碰它们。知道存在哪些差异,我正在使用
copy.copy()
克隆现有实例,然后应用这些更改使其表现得像一个新实例。import copy
from django.db import models
def copy_field(f):
fp = copy.copy(f)
fp.creation_counter = models.Field.creation_counter
models.Field.creation_counter += 1
if hasattr(f, "model"):
del fp.attname
del fp.column
del fp.model
# you may set .name and .verbose_name to None here
return fp
鉴于此功能,我使用以下内容创建新模型:
target_field_name = "name"
target_field = People._meta.get_field_by_name(target_field_name)[0]
model_fields = {}
model_fields["value"] = copy_field(target_field)
model_fields["value"].db_index = True
model_fields["__module__"] = People.__module__
NewModel = type("People_index_" + field_name, (models.Model,), model_fields)
有用!
关于django - 将 Django 字段描述从现有模型复制到新模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12222003/