django - 将 Django 字段描述从现有模型复制到新模型

标签 django django-models

我正在尝试根据现有模型中的字段动态生成新模型。两者都在 /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/

    相关文章:

    python - django-model-utils StatusModel 可以提供人类可读的状态选项吗?

    python - 从 Django 连接到 MySQL

    python - 在 Django 中设置拆卸登录注销的正确方法

    python - 如何使用 Postgres 在 Django 中计算从现在到 future 某个日期之间剩余的每月重复日期数

    python - Django - 限制查看项目的用户

    python - Django 管理员说 : Select a valid choice. That choice is not one of the available choices

    Django REST Framework 获取AuthToken 用户登录API View

    regex - 当正则表达式在数据库中并且值为字符串时使用 Django ORM Postgresql 正则表达式

    django - 如何使用 UserProfile 扩展 Django 身份验证模型 User,避免相关ObjectDoesNotExist 错误?

    django - Django框架中的Spring Interceptors/Filters相当于什么