如何在不定义内容类型或模型的情况下使用Django权限?

时间:2012-12-18 12:14:38

标签: django django-permissions

我想使用基于权限的系统来限制我的Django应用程序中的某些操作。这些操作无需与特定模型相关(例如,访问应用程序中的部分,搜索......),因此我无法直接使用stock permissions framework,因为Permission模型需要参考已安装的内容类型。

我可以编写自己的权限模型,但之后我必须重写Django权限中包含的所有好东西,例如:

我已经检查了一些应用,例如django-authoritydjango-guardian,但它们似乎通过允许每个对象的权限提供更多与模型系统耦合的权限。

有没有办法在没有为项目定义任何模型(UserGroup除外)的情况下重用此框架?

8 个答案:

答案 0 :(得分:93)

对于那些仍在搜索的人:

您可以创建没有数据库表的辅助模型。该模型可以为您的项目带来您需要的任何许可。无需处理ContentType或显式创建Permission对象。

function urlParam(name){
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
    // Need to decode the URL parameters, including putting in a fix for the plus sign
    // https://stackoverflow.com/a/24417399
    return results ? decodeURIComponent(results[1].replace(/\+/g, '%20')) : null;
}

from django.db import models class RightsSupport(models.Model): class Meta: managed = False # No database table creation or deletion \ # operations will be performed for this model. permissions = ( ('customer_rights', 'Global customer rights'), ('vendor_rights', 'Global vendor rights'), ('any_rights', 'Global any rights'), ) 之后,您可以像使用其他任何权限一样使用这些权限。

manage.py migrate

答案 1 :(得分:47)

关注Gonzalo's advice后,我使用了proxy modelcustom manager来处理虚拟内容类型的“无模型”权限。

from django.db import models
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType


class GlobalPermissionManager(models.Manager):
    def get_query_set(self):
        return super(GlobalPermissionManager, self).\
            get_query_set().filter(content_type__name='global_permission')


class GlobalPermission(Permission):
    """A global permission, not attached to a model"""

    objects = GlobalPermissionManager()

    class Meta:
        proxy = True

    def save(self, *args, **kwargs):
        ct, created = ContentType.objects.get_or_create(
            name="global_permission", app_label=self._meta.app_label
        )
        self.content_type = ct
        super(GlobalPermission, self).save(*args, **kwargs)

答案 2 :(得分:45)

Django的Permission模型requires a ContentType instance

我认为解决这个问题的方法是创建一个与任何模型无关的虚拟ContentTypeapp_labelmodel字段可以设置为任何字符串值。“ / p>

如果你想要一切都干净又漂亮,你可以创建一个Permission proxy model来处理虚拟ContentType的所有丑陋细节,并创建“无模型”权限实例。您还可以添加自定义管理器,过滤掉与实际模型相关的所有Permission个实例。

答案 3 :(得分:8)

修复了Chewie在Django 1.8中的回答,正如一些评论所要求的那样。

它在发行说明中说:

  

django.contrib.contenttypes.models.ContentType的名称字段已经存在   通过迁移删除并由属性替换。这意味着它不是   可以再通过此字段查询或过滤ContentType。

所以它是ContentType中引用中的'name',用于不在GlobalPermissions中。

当我修复它时,我得到以下内容:

from django.db import models
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType


class GlobalPermissionManager(models.Manager):
    def get_queryset(self):
        return super(GlobalPermissionManager, self).\
            get_queryset().filter(content_type__model='global_permission')


class GlobalPermission(Permission):
    """A global permission, not attached to a model"""

    objects = GlobalPermissionManager()

    class Meta:
        proxy = True
        verbose_name = "global_permission"

    def save(self, *args, **kwargs):
        ct, created = ContentType.objects.get_or_create(
            model=self._meta.verbose_name, app_label=self._meta.app_label,
        )
        self.content_type = ct
        super(GlobalPermission, self).save(*args)

GlobalPermissionManager类未更改,但包含完整性。

答案 4 :(得分:1)

您可以将记录插入数据库(显然可以根据需要编辑主键和外键),而不是编写和运行将记录插入数据库的代码。

insert into django_content_type(id,name,app_label,model) values (22,'app_permission','myapp','app_permission');
insert into auth_permission(id,name,content_type_id,codename) values (64,'Is Staff Member',22,'staff_member');

然后在您的应用程序管理员中,您将能够分配'是员工'对您的用户或群组。要在课程中检查此权限,您需要编写

from django.contrib.auth.decorators import permission_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

class MyClass(TemplateView):
    template_name = myapp/index.html'

    @method_decorator(permission_required(['myapp.staff_member'],raise_exception=True))
    def dispatch(self, *args, **kwargs):
        return super(MyClass, self).dispatch(*args, **kwargs)

答案 5 :(得分:1)

这是替代解决方案。首先问问自己:为什么不创建一个真正存在于DB但却永远不会被使用的Dummy-Model,除了持有权限?这并不好,但我认为这是有效且直接的解决方案。

from django.db import models

class Permissions(models.Model):

    can_search_blue_flower = 'my_app.can_search_blue_flower'

    class Meta:
        permissions = [
            ('can_search_blue_flower', 'Allowed to search for the blue flower'),
        ]

上述解决方案的好处是,您可以在源代码中使用变量Permissions.can_search_blue_flower,而不是使用文字字符串" my_app.can_search_blue_flower"。这意味着在IDE中减少拼写错误和更多自动完成。

答案 6 :(得分:1)

您可以将proxy model用于虚拟内容类型。

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType


class CustomPermission(Permission):

    class Meta:
        proxy = True

    def save(self, *args, **kwargs):
        ct, created = ContentType.objects.get_or_create(
            model=self._meta.verbose_name, app_label=self._meta.app_label,
        )
        self.content_type = ct
        super(CustomPermission, self).save(*args)

现在,您可以仅使用name模型中的codenameCustomPermission权限创建权限。

 CustomPermission.objects.create(name='Can do something', codename='can_do_something')

您可以在模板中查询和仅显示自定义权限。

 CustomPermission.objects.filter(content_type__model='custom permission')

答案 7 :(得分:1)

就我而言,对于任何更大的项目,我发现拥有一个并不真正属于我的项目数据模型的一部分的通用应用程序很有用本身 - 我通常将其称为“projectlibs”。这是一个简单的 django 应用程序,并在其中放入诸如用于导入的装置、可重复用于多个应用程序的模板标签等内容。其中一些是我发现自己经常重复使用的模板内容,因此拥有此类内容的额外好处在一个应用中,它可以被其他项目重复使用。

因此在 /projectlibs/models.py 中,您可以:

本质上,您可以创建那个“元应用程序”,并为内容类型分配一些虚拟类:

 class UserRightsSupport(models.Model):
    pass
    class Meta:
       default_permissions = ()        # disable defaults add, delete, view, change perms
       permissions = (("perm_name", "Verbose description"),
                   )