如何编写Django下仅允许内容创建者操作资源的自定义装饰器
Django 实现仅内容创建者可操作的自定义装饰器
1. 编写自定义书籍作者校验装饰器
from django.http import HttpResponseForbidden from django.shortcuts import get_object_or_404 from .models import Book def is_book_writer(function): def wrap(request, *args, **kwargs): # 从视图URL参数中获取书籍主键 book = get_object_or_404(Book, id=kwargs["pk"]) # 校验当前登录用户是否为该书籍的对应作者 if request.user == book.writer.profile.user: return function(request, *args, **kwargs) # 校验不通过返回403禁止访问 return HttpResponseForbidden("您没有权限操作该书籍资源") # 保留原函数的元信息 wrap.__doc__ = function.__doc__ wrap.__name__ = function.__name__ return wrap
2. 在类视图中挂载装饰器
和你现有使用的其他装饰器用法一致,用method_decorator包裹后绑定到dispatch方法即可:
@method_decorator(login_required(login_url='core:login'), name='dispatch') @method_decorator(allowed_users(allowed_roles=['writer']), name='dispatch') # 新增作者校验装饰器 @method_decorator(is_book_writer, name='dispatch') class BookDeleteView(BSModalDeleteView): model = Book template_name = 'book/book_delete.html' success_message = 'Success: book was deleted.' success_url = reverse_lazy('core:book_list')
3. 可选优化:通用化装饰器适配多模型
如果后续需要给其他模型也添加类似的所有者校验逻辑,可以改成可传参的通用装饰器,避免重复编码:
from django.http import HttpResponseForbidden from django.shortcuts import get_object_or_404 def is_content_owner(model_class, owner_field_path): def decorator(function): def wrap(request, *args, **kwargs): target_obj = get_object_or_404(model_class, id=kwargs["pk"]) # 按指定路径读取所有者字段 owner = target_obj for field in owner_field_path.split("."): owner = getattr(owner, field) if request.user == owner: return function(request, *args, **kwargs) return HttpResponseForbidden("您没有权限操作该资源") wrap.__doc__ = function.__doc__ wrap.__name__ = function.__name__ return wrap return decorator
使用时直接传入对应模型和所有者字段路径即可:
@method_decorator(is_content_owner(Book, "writer.profile.user"), name='dispatch')
注意事项
- 请确保URL路由中传递给视图的主键参数名和装饰器中读取的参数名一致,如果你路由中使用
book_id而非pk作为参数名,需要将kwargs["pk"]修改为kwargs["book_id"] - 装饰器执行顺序为从上到下,建议将登录校验、角色校验放在所有者校验之前,减少无效数据库查询
内容的提问来源于stack exchange,提问作者ahmed belkhiri
相关产品推荐
相关产品推荐

