如何在不定义内容types或模型的情况下使用Django权限?
我想使用基于权限的系统来限制我的Django应用程序中的某些操作。 这些操作不需要与特定模型相关(例如访问应用程序中的部分,search…),所以我不能直接使用股票权限框架 ,因为Permission
模型需要对已安装内容types的引用。
我可以编写自己的权限模型,但是我必须重写包含在Django权限中的所有好东西,比如:
- 向用户和组分配权限的可能性。
-
permission_required
装饰器 。 -
User.has_perm
和相关的用户方法。 -
perms
模板variables 。 - …
我已经检查了一些像django-authority和django-guardian这样的应用程序,但是它们似乎通过允许每个对象的权限来提供更多的耦合到模型系统的权限。
有没有一种方法可以重用这个框架,而没有定义任何模型(除User
和Group
)的项目?
Django的Permission
模型需要一个ContentType
实例 。
我想有一种方法是创build一个与任何模型无关的虚拟ContentType
( app_label
和model
字段可以设置为任何string值)。
如果您希望所有内容都干净整洁,则可以创build一个Permission
代理模型 ,以处理虚拟ContentType
所有丑陋细节,并创build“无模型”权限实例。 您还可以添加一个自定义pipe理器,用于过滤掉与真实模型相关的所有Permission
实例。
遵循Gonzalo的build议 ,我使用了一个代理模型和一个自定义的pipe理器来处理我的“无模型”的权限和一个虚拟的内容types。
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)
对于那些还在寻找的人来说:
您可以创build没有数据库表的辅助模型。 该模型可以为您的项目带来任何您需要的权限。 没有必要处理ContentType或显式创buildPermission对象。
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_rigths', 'Global customer rights'), ('vendor_rights', 'Global vendor rights'), ('any_rights', 'Global any rights'), )
在manage.py migrate
您可以像使用其他权限一样使用这些权限。
# Decorator @permission_required('app.customer_rights') def my_search_view(request): … # Inside a view def my_search_view(request): request.user.has_perm('app.customer_rights') # In a template # The currently logged-in user's permissions are stored in the template variable {{ perms }} {% if perms.app.customer_rigths %} <p>You can do any customer stuff</p> {% endif %}
修正了Django 1.8中Chewie的回答,正如一些评论中所要求的那样。
它在发行说明中说:
django.contrib.contenttypes.models.ContentType的名称字段已被迁移删除,并由属性取代。 这意味着无法再通过此字段查询或过滤ContentType。
所以它是ContentType中引用的“名称”,不在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类保持不变,但包含为了完整性。
而不是编写和运行这个代码插入到数据库中的logging,你可以插入logging到你的数据库(显然编辑主键和外键按需要)
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');
然后在您的应用程序pipe理员中,您可以将“职员”分配给您的用户或组。 要在你的课堂上检查这个权限,你会写
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)