创建Django作出反应的自定义异常

时间:2010-02-19 19:39:13

标签: django

对于我的网站,我创建了一个实现模型级读取权限的抽象模型。系统的该部分已完成并正常运行。权限模型公开的方法之一是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)

4 个答案:

答案 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