Python django:作为异常引发BadRequest?
是否可以在django中将Python django:作为异常引发BadRequest?,python,django,exception-handling,httpresponse,Python,Django,Exception Handling,Httpresponse,是否可以在django中将BadRequest作为异常引发 我知道你可以提出404[1] 用例:在助手方法中,我从request.GET加载json。如果json是因为浏览器(IE)剪切了url而被剪切的,我想提出一个匹配的异常 BadRequest异常看起来很合适,但到目前为止,django中似乎没有这样的异常 在1.6中有一个可疑的操作异常。但这与我的情况不符,因为它与安全无关 当然,我可以试试..除了在视图方法中我的helper方法周围,但这不是干的 是否有人提出了一个解决方案,在我的助手
BadRequest
作为异常引发
我知道你可以提出404[1]
用例:在助手方法中,我从request.GET加载json。如果json是因为浏览器(IE)剪切了url而被剪切的,我想提出一个匹配的异常
BadRequest异常看起来很合适,但到目前为止,django中似乎没有这样的异常
在1.6中有一个可疑的操作异常。但这与我的情况不符,因为它与安全无关
当然,我可以试试..除了在视图方法中我的helper方法周围,但这不是干的
是否有人提出了一个解决方案,在我的助手方法的每次调用中都不需要尝试..异常
[1]
更新
代码示例:
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
您需要定制中间件来处理您提出的异常。 利用自定义异常检查中间件中的这种情况
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")
我不知道你把BadRequest作为例外是什么意思 您可以通过显式使用HttpResponse的相关子类,或通过向正常响应中添加一个
status
参数,返回带有任何状态代码的响应。已准备就绪。作为:
已编辑到期OP更新问题
您可以创建自己的助手,并将try-catch块封装到其中
def myJsonDec(str):
try:
...
其他答案解释了如何返回状态为400的HTTP响应 如果你想挂接到Django的,你可以引发一个异常或者它的一个子类 请参阅文档和 在您的示例中,它看起来像:
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
作为@coldmind回答(在中间件层转换异常)的替代方法,您可以在视图函数上放置一个decorator,它也可以做同样的事情。就我个人而言,我更喜欢这个,因为它只是一个简单的老Python,不需要我对Django中间件的工作原理一窍不通 您不希望意识流内联视图函数中的所有功能(这使您的视图模块依赖于项目的所有其他模块,导致“一切都取决于其他一切”架构),相反,如果视图只知道http,则更好。它从请求中提取您需要的内容,委托给其他一些“业务逻辑”功能。业务逻辑可能会委托给其他模块(例如,数据库代码或其他外部系统的接口)。然后,来自业务逻辑的返回值最终由view函数转换为http响应 但是如何将错误从业务逻辑(或它所委托的任何对象)传递回视图函数呢?由于许多原因,使用返回值是令人厌烦的。例如,这些错误返回值必须从整个代码库中传播回视图。这通常非常混乱,因为您已经将函数的返回值用于其他目的 处理这一问题的自然方法是使用异常,但Django视图本身不会将未捕获的异常转换为返回的HTTP状态代码(如OP所述,有几个特殊情况除外) 所以。我写了一个装饰者来应用我的观点。装饰程序将各种引发的异常类型转换为不同的返回的django.http.HttpResponseXXX值。e、 g:
# 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)
根据具体情况,您可能会发现同一个装饰器可以处理许多或所有视图函数。我认为一种简单的方法是定义您自己的BadRequestException并在调用的函数中引发它
从django.http导入HttpResponseBadRequest,HttpResponse
类BadRequestException(异常):
定义初始化(self,message='',*args,**kwargs):
self.message=消息
定义我的视图(请求):
尝试:
数据=从另一个函数()获取数据
除BadRequestException外,如e:
返回HttpResponseBadRequest(e.message)
过程数据(数据)
返回HttpResponse('谢谢')
def从另一个函数()获取数据:
引发BadRequestException(消息='something Error')
def过程_数据(数据):
通过
为什么不直接返回django.http.HttpResponseBadRequest
?如果你想保持干燥,让你的助手方法返回适当的HttpResponse
类,或者在其周围创建另一个快捷方式,比如load\u json\u或\u bad\u request()
@ambi我不想返回django.http.HttpResponseBadRequest
,因为我的方法返回解析的数据,除了输入数据被破坏之外。@guettli更新后,我认为您应该引发一个自定义异常,并按照coldmind的建议在中间件中处理它。这与get\u object\u或\u 404使用的机制相同,我更新了这个问题。请看代码示例。HttpResponseBadRequest异常非常好,但是开箱即用的Django并没有以这种方式概括处理其他HTTP状态值。(也许他们很难做到这一点——将异常类型映射到http状态代码可能是特定于应用程序的,除非您只想为每个http状态代码显式创建一个异常类型,这意味着您的业务逻辑和它所委托的代码将充满关于http状态代码的知识。)我在这页下面的某个地方有一个答案,试图解决这个问题,但这是一堆代码。HttpResponseBadRequest不是一个例外,它不能被提出。我添加了一个代码示例。我希望现在更清楚。我不想查看函数返回类型,而是基于返回响应良好的点,记住注释行是不正确的,因为您在任何情况下都返回响应(以相同的方式),而不仅仅是在“您的异常”情况下。这可能是完美的,也可能是错误的,这取决于具体情况,我只是对注释行进行了澄清,因此这适用于<1.10版本,请参见:我认为这里的总体模式很好,但是
# 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)