Python django:将 BadRequest 作为异常提出?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25422176/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 20:12:05  来源:igfitidea点击:

django: raise BadRequest as exception?

pythondjangoexception-handlinghttpresponse

提问by guettli

Is it possible to raise BadRequestas exception in django?

是否可以BadRequest在 Django 中引发异常?

I have seen that you can raise a 404 [1].

我已经看到您可以提出 404 [1]。

Use case: in a helper method I load a json from request.GET. If the json was cut since the browser (IE) cut the url, I would like to raise a matching exception.

用例:在辅助方法中,我从 request.GET 加载一个 json。如果 json 是因为浏览器 (IE) 剪切 url 后被剪切的,我想提出一个匹配的异常。

A BadRequest exception looks appropriate, but up to now there seems to no such exception in django.

BadRequest 异常看起来很合适,但到目前为止,django 中似乎没有这样的异常。

In 1.6 there is a SuspiciousOperation exception. But this does not match in my case, since it is not security related.

在 1.6 中有一个 SuspiciousOperation 异常。但这与我的情况不符,因为它与安全无关。

Of course I could put a try..except around my helper method in the view method, but this is not DRY.

当然,我可以尝试……除了视图方法中的辅助方法,但这不是 DRY。

Has someone a solution where I don't need a try..exception around every call of my helper method?

有人有一个解决方案,我不需要在每次调用我的辅助方法时都进行 try..exception 吗?

[1] https://docs.djangoproject.com/en/1.6/ref/exceptions/#django.core.urlresolvers.Resolver404

[1] https://docs.djangoproject.com/en/1.6/ref/exceptions/#django.core.urlresolvers.Resolver404

Update

更新

Code example:

代码示例:

def my_view(request):
    data=load_data_from_request(request) # I don't want a try..except here: DRY
    process_data(data)
    return django.http.HttpResponse('Thank you')

def load_data_from_request(request):
    try:
        data_raw=json.loads(...)
    except ValueError, exc:
        raise BadRequest(exc)
    ...
    return data

采纳答案by coldmind

You need custom middleware to handle exception what you raise. Utilize custom exceptions to check for this condition in middleware.

您需要自定义中间件来处理您提出的异常。利用自定义异常检查中间件中的这种情况。

class ErrorHandlingMiddleware(object):
    def process_exception(self, request, exception):
        if not isinstance(exception, errors.ApiException): # here you check if it yours exception
            logger.error('Internal Server Error: %s', request.path,
                exc_info=traceback.format_exc(),
                extra={
                    'request': request
                }
            )
        # if it yours exception, return response with error description
        try:
            return formatters.render_formatted_error(request, exception) # here you return response you need
        except Exception, e:
            return HttpResponseServerError("Error During Error Processing")

回答by Daniel Roseman

I'm not sure what you mean by raising BadRequest as an exception.

我不确定您将 BadRequest 作为例外是什么意思。

You can return a response with any status code you like, either by explicitly using the relevant subclass of HttpResponse, or by adding a statusparameter to the normal response.

您可以通过显式使用 HttpResponse 的相关子类或通过向status正常响应添加参数来返回带有您喜欢的任何状态代码的响应。

回答by dani herrera

HttpResponseBadRequestis ready to use. It is implementedas:

HttpResponseBadRequest可以使用了。它实现为:

class HttpResponseBadRequest(HttpResponse):
    status_code = 400

Editeddue OP updated question.

编辑到期 OP 更新问题。

You can create your own helper and encapsulate try-catch block into it.

您可以创建自己的帮助程序并将 try-catch 块封装到其中。

def myJsonDec(str):
    try:
        ...

回答by yprez

The other answers are explaining how to return an HTTP response with 400 status.

其他答案解释了如何返回状态为 400 的 HTTP 响应。

If you want to hook into Django's 400 error handling, you can raise a SuspiciousOperationexception or a subclass of it.

如果您想使用 Django 的400 错误处理,您可以引发SuspiciousOperation异常或其子类。

See the docs hereand here.

请参阅此处此处的文档。

In your example it would look like:

在您的示例中,它看起来像:

from django.core.exceptions import SuspiciousOperation

def load_data_from_request(request):
    try:
        data_raw = json.loads(...)
    except ValueError:
        raise SuspiciousOperation('Invalid JSON')
    # ...
    return data

回答by Jonathan Hartley

As an alternative to @coldmind's answer (converting exceptions in a middleware layer), you could put a decorator on your view function which does the same thing. Personally I prefer this, because it's just plain-old-Python, and doesn't require me dust off my knowledge of how Django middleware works.

作为@coldmind 答案的替代方案(在中间件层中转换异常),您可以在视图函数上放置一个装饰器,它执行相同的操作。就我个人而言,我更喜欢这个,因为它只是普通的 Python,不需要我了解 Django 中间件的工作原理。

You don't want to stream-of-conciousness inline all functionality in your view functions (this makes your view module depend on all your project's other modules, leading to 'everything depends on everything else' architecture) Instead, it's better if the view just knows about http. It extracts what you need from the request, delegates to some other 'business logic' function. The business logic might delegate to other modules (e.g. database code or interfaces to other external systems.) Then finally the return value from your business logic is converted into an http response by the view function.

您不希望意识流内联视图函数中的所有功能(这使您的视图模块依赖于您项目的所有其他模块,导致“一切都取决于其他一切”架构)相反,如果视图只知道http。它从请求中提取您需要的内容,委托给其他一些“业务逻辑”功能。业务逻辑可能会委托给其他模块(例如数据库代码或其他外部系统的接口)。然后最终来自业务逻辑的返回值被视图函数转换为 http 响应。

But how to communicate errors back to the view function from the business logic (or whatever it delegates to)? Using return values is irksome for many reasons. For example, these error return values will have to be propogated back to the view from all through your whole codebase. This is often cripplingly messy because you will already be using the return values of functions for other purposes.

但是如何将错误从业务逻辑(或它委托给的任何东西)传达回视图函数呢?出于多种原因,使用返回值令人厌烦。例如,这些错误返回值必须从整个代码库中传播回视图。这通常非常混乱,因为您已经将函数的返回值用于其他目的。

The natural way to deal with this is to use exceptions, but the Django view won't, by itself, convert uncaught exceptions into returned HTTP status codes (except for a couple of special cases, as the OP says.)

处理这个问题的自然方法是使用异常,但 Django 视图本身不会将未捕获的异常转换为返回的 HTTP 状态代码(除了一些特殊情况,正如 OP 所说。)

So. I write a decorator to apply to my view. The decorator converts various raised exception types into different returned django.http.HttpResponseXXX values. e.g:

所以。我写了一个装饰器来应用我的视图。装饰器将各种引发的异常类型转换为不同的返回 django.http.HttpResponseXXX 值。例如:

# This might be raised by your business logic or database code, if they get
# called with parameters that turn out to be invalid. The database code needs
# know nothing about http to do this. It might be best to define these exception
# types in a module of their own to prevent cycles, because many modules 
# might need to import them.
class InvalidData(Exception):
    pass

# This decorator is defined in the view module, and it knows to convert
# InvalidData exceptions to http status 400. Add whatever other exception types
# and http return values you need. We end with a 'catch-all' conversion of
# Exception into http 500.
def exceptions_to_http_status(view_func):
    @wraps(view_func)
    def inner(*args, **kwargs):
        try:
            return view_func(*args, **kwargs)
        except InvalidData as e:
            return django.http.HttpResponseBadRequest(str(e))   
        except Exception as e:
            return django.http.HttpResponseServerError(str(e))
     return inner

 # Then finally we define our view, using the decorator.

 @exceptions_to_http_status
 def myview(self, request):
     # The view parses what we need out of incoming requests
     data = request.GET['somearg']

     # Here in the middle of your view, delegate to your business logic,
     # which can just raise exceptions if there is an error.
     result = myusecase(data)

     # and finally the view constructs responses
     return HttpResponse(result.summary)

Depending on circumstance, you might find the same decorator could work on many, or all, of your view functions.

根据情况,您可能会发现同一个装饰器可以用于您的许多或所有视图函数。