【问题标题】:Dynamic Meta attributes for Django Models?Django 模型的动态元属性?
【发布时间】:2009-04-07 14:07:28
【问题描述】:

我正在尝试使用模型继承向我的所有 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 使用自省来构造模型类,所以我不确定在类的 __init__() 期间添加权限是否会起作用。对于我当前的实现,每次访问模型实例时,它都会附加另一个权限元组。

【问题讨论】:

    标签: django django-models


    【解决方案1】:

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

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

    使用继承无法实现您的目标。您真正需要的是Python metaclass

    这个元类在定义之前动态重写您的ModelAModelB 类定义,因此它不需要ModelA 实例,并且可用于syncdb。由于 Django 的模型首先也使用元类来构建 Meta 对象,因此唯一的要求是您的元类必须继承自与 Django 模型相同的元类。

    这里有一些示例代码(Python 2):

    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_{0.module_name}'.format(klas._meta),
                    u'Can view {0.verbose_name}'.format(klas._meta))
            )
    
            return klas
    
    class ModelA(models.Model):
    
        __metaclass__ = CustomModelMetaClass
    
        test = models.CharField(max_length=5)
    

    Python 3:

    from django.db.models.base import ModelBase
    
    class CustomModelMetaClass(ModelBase):
    
        def __new__(cls, name, bases, attrs):
            klas = super().__new__(cls, name, bases, attrs)
            klas._meta.permissions.append(
                (
                    'view_{0.module_name}'.format(klas._meta),
                    'Can view {0.verbose_name}'.format(klas._meta))
            )
    
            return klas
    
    class ModelA(models.Model, metaclass=CustomModelMetaClass):
    
        test = models.CharField(max_length=5)
    

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

    【讨论】:

    • +1 获取在 django 相关问题中编写自定义元类的示例。这东西好难找!
    • 我知道这是赞成票的用途,而且这是一个旧线程,但是......该死的,Jarret。 Django 和 Python 知识渊博的知识水平需要拿出这个答案,然后简单明了地解释是令人难以置信的。感谢您让互联网变得更加有用。
    • 我不知道你是谁,@General_Mayhem,但你刚刚成就了我的一年。感谢您在这么旧的帖子上制作漂亮的 cmets!
    • 我是一个刚开始尝试(现在已经成功)解决与 OP 相同的问题的 Django 开发人员,但他甚至不知道 Python 有元类,更不用说确切地如何应用他们在这种情况下,并且非常沮丧,因为关于 Django 的每个页面都使用了它的所有关键字。
    • 请注意,对于 Python 3,您需要 class ModelA(models.Model, metaclass=CustomModelMetaClass)(而不是 __metaclass__)。
    【解决方案2】:

    尝试使用自定义管理器:

    #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')
    

    【讨论】:

    • 我忘了说:这仅适用于每个表的表结构相同的情况。
    猜你喜欢
    • 2016-03-17
    • 1970-01-01
    • 2018-12-06
    • 2011-12-09
    • 2023-03-27
    • 2018-06-27
    • 2015-08-28
    • 2016-12-15
    • 1970-01-01
    相关资源
    最近更新 更多