对于我的网站,我创建了一个抽象模型,它实现了模型级读取权限.系统的该部分已完成并正常运行.许可模型公开的方法之一是is_safe(user)可以手动测试是否允许用户查看该模型.
我想要做的是添加一个方法continue_if_safe,可以在任何模型实例上调用其效果,而不是返回一个布尔值,就像is_safe它首先测试是否可以查看模型,然后在False的情况下,它会将用户重定向到登录页面(如果他们尚未登录)或者如果他们已登录则返回403错误.
理想用途:
model = get_object_or_404(Model, slug=slug)
model.continue_if_safe(request.user)
# ... remainder of code to be run if it's safe down here ...
Run Code Online (Sandbox Code Playgroud)
我偷看了get_object_or_404是如何工作的,它抛出了一个Http404似乎有意义的错误.但是,问题是似乎没有等效的重定向或403错误.最好的方法是什么?
(非工作)continue_if_safe方法:
def continue_if_safe(self, user):
if not self.is_safe(user):
if user.is_authenticated():
raise HttpResponseForbidden()
else:
raise HttpResponseRedirect('/account/')
return
Run Code Online (Sandbox Code Playgroud)
最终解决方案的代码,以防其他"堆栈器"需要一些帮助:
在抽象模型中:
def continue_if_safe(self, user):
if not self.is_safe(user):
raise PermissionDenied()
return
Run Code Online (Sandbox Code Playgroud)
中间件捕获视图:
class PermissionDeniedToLoginMiddleware(object):
def process_exception(self, request, exception):
if type(exception) == PermissionDenied:
if not request.user.is_authenticated():
return HttpResponseRedirect('/account/?next=' + request.path)
return None
Run Code Online (Sandbox Code Playgroud)
视图中的用法(非常简短和甜蜜):
model = get_object_or_404(Model, slug=slug)
model.continue_if_safe(request.user)
Run Code Online (Sandbox Code Playgroud)
Clé*_*ent 10
对于禁止(403)错误,您可以引发PermissionDenied异常(from django.core.exceptions).
对于重定向行为,没有内置的方法来处理您在问题中描述的方式.您可以编写一个自定义中间件来捕获您的异常并重定向process_exception.
我做了一个小的中间件,它返回你的Exception类的render方法返回的内容.现在,您可以在任何视图中抛出自定义异常(使用渲染方法).
class ProductNotFound(Exception):
def render(self, request):
return HttpResponse("You could ofcourse use render_to_response or any response object")
Run Code Online (Sandbox Code Playgroud)
pip install -e git+http://github.com/jonasgeiregat/django-excepted.git#egg=django_excepted
Run Code Online (Sandbox Code Playgroud)
并添加django_excepted.middleware.ExceptionHandlingMiddleware到您的MIDDLEWARE_CLASSES.