Django模型的动态元属性?

时间:2009-04-07 14:07:28

标签: 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'),)

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

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):
    ...

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

2 个答案:

答案 0 :(得分:24)

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

  • 运行syncdb时,它们需要在类级别可用才能填充auth_permission表(并且您的方法需要一个实例,在syncdb期间不会生成)
  • 即使您确实将其添加到_meta.permissions中的__init__User对象也不会在任何权限检查调用中将其选中,因为这些会查询数据库中的权限表(和那个表的缓存,在那)。

这里你真正需要的是一个元类...你的目标无法通过继承来实现。元类在定义之前动态地重写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)

请注意,此情况下的权限仅在syncdb上写入。如果您需要在运行时根据用户动态更改权限,则需要提供自己的authentication backend

答案 1 :(得分:0)

尝试使用自定义管理器:

#create a custom manager
class DynTableNameManager(models.Manager):
    #overwrite all() (example)
    #provide table_name
    def all(self, table_name):
        from django.db import connection
        cursor = connection.cursor()
        cursor.execute("""
            SELECT id, name
            FROM %s
            """ % table_name)
        result_list = []
        for row in cursor.fetchall():
            p = self.model(id=row[0], name=row[1])
            result_list.append(p)
        return result_list

#cerate a dummy table
class DummyTable(models.Model):
    name = models.CharField ( max_length = 200 )
    objects = DynTableNameManager()

像这样使用:

f = DummyTable.objects.all('my_table_name')