我正在生成一个基于抽象模型类 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
