用`type`动态创建Django模型

n

我有20个+ MySQL表,prm_aprm_b,...有相同的基本结构,但不同的名字,我想不用写每一个用手工将它们与Django的模型类相关联。因此,我有雄心壮志,因此我想尝试将其type()用作班级工厂:

以下作品:

def get_model_meta_class(prm_name):
    class Meta:
        app_label = 'myapp'
    setattr(Meta, 'db_table', 'prm_%s' % prm_name)
    return Meta

prm_class_attrs = {
    'foo': models.ForeignKey(Foo),
    'val': models.FloatField(),
    'err': models.FloatField(blank=True, null=True),
    'source': models.ForeignKey(Source),
    '__module__': __name__,
}

###
prm_a_attrs = prm_class_attrs.copy()
prm_a_attrs['Meta'] = get_model_meta_class('a')
Prm_a = type('Prm_a', (models.Model,), prm_a_attrs)

prm_b_attrs = prm_class_attrs.copy()
prm_b_attrs['Meta'] = get_model_meta_class('b')
Prm_b = type('Prm_b', (models.Model,), prm_b_attrs)
###

但是,如果我尝试生成模型类,如下所示:

###
prms = ['a', 'b']
for prm_name in prms:
    prm_class_name = 'Prm_%s' % prm_name
    prm_class = type(prm_class_name, (models.Model,), prm_class_attrs)
    setattr(prm_class, 'Meta', get_model_meta_class(prm_name))
    globals()[prm_class_name] = prm_class
###

type()在线路上得到一个奇怪的异常__module__实际上是在prm_class_attrs字典中):

File ".../models.py", line 168, in <module>
    prm_class = type(prm_class_name, (models.Model,), prm_class_attrs)
  File ".../lib/python2.7/site-packages/django/db/models/base.py", line 79, in __new__
    module = attrs.pop('__module__')
KeyError: u'__module__' 

因此,我有两个问题:第二种方法有什么问题,这甚至是创建类模型的正确方法吗?

好的-感谢@Anentropic,我发现prm_class_attrs字典中的项目在创建类时被Python弹出。现在,它可以正常工作,但前提是我必须这样做:

attrs = prm_class_attrs.copy()
attrs['Meta'] = get_model_meta_class(prm_name)
prm_class = type(prm_class_name, (models.Model,), attrs)

如果我将Meta班级定为

setattr(prm_class, 'Meta', get_model_meta_class(prm_name))

我真的不知道为什么会这样,但是至少我现在可以正常工作了。

该imediate原因是因为你没有做prm_class_attrs.copy()你的for循环,所以__modules__关键是在字典上的第一次迭代得到弹出

至于为什么这不起作用:

setattr(prm_class, 'Meta', get_model_meta_class(prm_name))

...这与Djangomodels.Model具有元类这一事实有关但这是一个Python元类,可自定义模型类的创建,Meta而与Django模型内部类无关(后者仅提供有关模型的“元”信息)。

实际上,尽管您在中定义类时看起来如何,但models.py结果类却没有Meta属性:

class MyModel(models.Model):
    class Meta:
        verbose_name = 'WTF'

>>> MyModel.Meta
AttributeError: type object 'MyModel' has no attribute 'Meta'

(您可以Meta直接访问该类,但别名为MyModel._meta

您定义的模型models.py实际上比实际模型类更多地是模型类的模板。这就是为什么当您访问模型实例上的字段属性时,会获得该字段的,而不是字段对象本身的原因。

Django模型继承可以简化您的工作:

class GeneratedModelBase(models.Model):
    class Meta:
        abstract = True
        app_label = 'myapp'

    foo = models.ForeignKey(Foo)
    val = models.FloatField()
    err = models.FloatField(blank=True, null=True)
    source = models.ForeignKey(Source)

def generate_model(suffix):
    prm_class_name = 'Prm_%s' % prm_name
    prm_class = type(
        prm_class_name,
        (GeneratedModelBase,),
        {
            # this will get merged with the attrs from GeneratedModelBase.Meta
            'Meta': {'db_table', 'prm_%s' % prm_name},
            '__module__': __name__,
        }
    )
    globals()[prm_class_name] = prm_class
    return prm_class

prms = ['a', 'b']
for prm_name in prms:
    generate_model(prm_name)

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章