Skip to main content
 首页 » 编程设计

python之将动态生成的模型添加到 Django 项目中的 models.py

2025年05月04日35insus

我正在生成一个基于抽象模型类 AbstractAttr 和一个普通模型(比如 Foo)的 Django 模型。

我希望我的 foo/models.py 看起来像这样:

from bar.models import Attrs 
# ... 
class Foo(models.Model): 
    .... 
    attrs = Attrs() 

在模拟字段的 Attrs 类中,我有一个 contribute_to_class,它使用 type() 生成所需的模型。生成的模型c称为FooAttr。

一切正常。如果我迁移,我会看到 FooAttr 出现在正确的表中。

除了一件事。

我希望能够from foo.models import FooAttr。不知何故,我生成的 FooAttr 类未绑定(bind)到生成它的 models.py 文件。

如果我将 models.py 更改为:

class Foo(models.Model): 
    # ... 
 
FooAttr = generate_foo_attr_class(...) 

它有效,但这不是我想要的(例如,这会强制开发人员猜测生成的类名)。

我想要的是不是可以像第一个示例中那样定义类并将其绑定(bind)到特定的 models.py 模块?

项目(pre-Alpha)在这里(在 develop 分支): https://github.com/zostera/django-mav

一些相关代码:

def create_model_attribute_class(model_class, class_name=None, related_name=None, meta=None): 
    """ 
    Generate a value class (derived from AbstractModelAttribute) for a given model class 
    :param model_class: The model to create a AbstractModelAttribute class for 
    :param class_name: The name of the AbstractModelAttribute class to generate 
    :param related_name: The related name 
    :return: A model derives from AbstractModelAttribute with an object pointing to model_class 
    """ 
 
    if model_class._meta.abstract: 
        # This can't be done, because `object = ForeignKey(model_class)` would fail. 
        raise TypeError("Can't create attrs for abstract class {0}".format(model_class.__name__)) 
 
    # Define inner Meta class 
    if not meta: 
        meta = {} 
    meta['app_label'] = model_class._meta.app_label 
    meta['db_tablespace'] = model_class._meta.db_tablespace 
    meta['managed'] = model_class._meta.managed 
    meta['unique_together'] = list(meta.get('unique_together', [])) + [('attribute', 'object')] 
    meta.setdefault('db_table', '{0}_attr'.format(model_class._meta.db_table)) 
 
    # The name of the class to generate 
    if class_name is None: 
        value_class_name = '{name}Attr'.format(name=model_class.__name__) 
    else: 
        value_class_name = class_name 
 
    # The related name to set 
    if related_name is None: 
        model_class_related_name = 'attrs' 
    else: 
        model_class_related_name = related_name 
 
    # Make a type for our class 
    value_class = type( 
        str(value_class_name), 
        (AbstractModelAttribute,), 
        dict( 
            # Set to same module as model_class 
            __module__=model_class.__module__, 
            # Add a foreign key to model_class 
            object=models.ForeignKey( 
                model_class, 
                related_name=model_class_related_name 
            ), 
            # Add Meta class 
            Meta=type( 
                str('Meta'), 
                (object,), 
                meta 
            ), 
        )) 
 
    return value_class 
 
 
class Attrs(object): 
    def contribute_to_class(self, cls, name): 
        # Called from django.db.models.base.ModelBase.__new__ 
        mav_class = create_model_attribute_class(model_class=cls, related_name=name) 
        cls.ModelAttributeClass = mav_class 

请您参考如下方法:

我看到您从 models.py 中创建模型,所以我认为您应该能够将它添加到模块的全局变量中。这个怎么样:

new_class = create_model_attribute_class(**kwargs) 
globals()[new_class.__name__] = new_class 
del new_class  # no need to keep original around