Django模型的动态元属性?

use*_*478 9 django django-models

我试图使用模型继承为我的所有Django模型添加动态Meta属性,但我无法让它工作.我有一个权限,我想添加到我的所有模型,如下所示:

class ModelA(models.Model):
    class Meta:
        permisssions =(('view_modela','Can view Model A'),)   

class ModelB(models.Model):
    class Meta:
        permisssions =(('view_modelb','Can view Model B'),)
Run Code Online (Sandbox Code Playgroud)

我尝试创建一个这样的抽象基类:

class CustomModel(models.Model):
    def __init__(self, *args, **kwargs):
        self._meta.permissions.append(('view_'+self._meta.module_name, u'Can view %s' % self._meta.verbose_name))
        super(CustomModel,self).__init__(*args, **kwargs)

class ModelA(CustomModel):
    ....

class ModelB(CustomModel):
    ...
Run Code Online (Sandbox Code Playgroud)

但它不起作用.这是正确的方法吗?因为Django使用内省来构造Model类,所以我不确定__init__()在类中添加权限是否会起作用.使用我当前的实现,每次访问模型实例时,它都会附加另一个权限元组.

Jar*_*die 25

你的直觉是对的,这是行不通的.在Django中,权限存储在数据库中,这意味着:

  • 运行syncdb时,它们需要在类级别可用才能填充auth_permission表(并且您的方法需要一个实例,在syncdb期间不会生成该实例)
  • 即使你将它添加到_meta.permissions__init__User对象不会把它捡起来的任何权限检查调用,因为这些咨询DB中的权限表(并表的高速缓存,在那个).

你真正需要的是一个元类......你的目标不能通过继承来实现.元类在定义之前动态地重写ModelAModelB类定义,因此它不需要ModelA实例,并且可用于syncdb.由于Django的模型也首先使用元类来构建Meta对象,唯一的要求是你的元类必须继承与Django模型相同的元类.这是一些示例代码:

from django.db.models.base import ModelBase

class CustomModelMetaClass(ModelBase):

    def __new__(cls, name, bases, attrs):
        klas = super(CustomModelMetaClass, cls).__new__(cls, name, bases, attrs)
        klas._meta.permissions.append(('view_' + klas._meta.module_name, u'Can view %s' % klas._meta.verbose_name))

        return klas

class ModelA(models.Model):

    __metaclass__ = CustomModelMetaClass

    test = models.CharField(max_length=5)
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下的权限将仅写入syncdb.如果需要在运行时根据用户动态更改权限,则需要提供自己的身份验证后端.

  • +1表示在django相关问题中编写自定义元类的示例.这东西很难找到! (3认同)