对于我的网站,我创建了一个实现模型级读取权限的抽象模型。系统的该部分已完成并正常运行。权限模型公开的方法之一是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 ...
我看看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
最终解决方案的代码,以防其他“堆叠器”需要一些帮助:
在抽象模型中:
def continue_if_safe(self, user):
if not self.is_safe(user):
raise PermissionDenied()
return
视图被中间件捕获:
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
视图中的用法(非常简短和甜蜜):
model = get_object_or_404(Model, slug=slug)
model.continue_if_safe(request.user)
答案 0 :(得分:10)
对于禁止(403)错误,您可以引发PermissionDenied
例外(来自django.core.exceptions
)。
对于重定向行为,没有内置的方式来处理您在问题中描述的方式。您可以编写一个自定义中间件来捕获您的异常并重定向到process_exception
。
答案 1 :(得分:5)
我做了一个小的中间件,它返回你的Exception类的render方法返回的内容。现在,您可以在任何视图中抛出自定义异常(使用渲染方法)。
class ProductNotFound(Exception):
def render(self, request):
return HttpResponse("You could ofcourse use render_to_response or any response object")
pip install -e git+http://github.com/jonasgeiregat/django-excepted.git#egg=django_excepted
并将django_excepted.middleware.ExceptionHandlingMiddleware
添加到您的MIDDLEWARE_CLASSES
。
答案 2 :(得分:2)
Django烦人的解决方案:
from annoying.exceptions import Redirect
...
raise Redirect('/') # or a url name, etc
答案 3 :(得分:1)
你想为此使用装饰器。查找login_required
示例。基本上,装饰者将允许您检查安全性,然后返回 HttpResponseRedirect()
,如果它不安全。
您的代码最终会看起来像这样:
@safety_check:
def some_view(request):
#Do Stuff