Djangoの例外としてBadRequest
を上げることは可能ですか?
私はあなたが404を上げることができることを見ました[1]。
使用例:ヘルパーメソッドで、request.GETからjsonをロードします。ブラウザ(IE)がURLをカットした後でjsonがカットされた場合、一致する例外を発生させたいと思います。
BadRequest例外は適切に見えますが、現在のところ、Djangoにはそのような例外はありません。
1.6では、SuspiciousOperation例外があります。しかし、これはセキュリティに関連しないため、私の場合は一致しません。
もちろん、viewメソッドのヘルパーメソッドを除いてtry..exceptを置くこともできますが、これはDRYではありません。
誰かが私のヘルパーメソッドのすべての呼び出しの周りにtry..exceptionを必要としない解決策を持っていますか?
[1] https://docs.djangoproject.com/en/1.6/ref/exceptions/#Django.core.urlresolvers.Resolver404
更新
コード例:
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")
他の回答は、400ステータスのHTTP応答を返す方法を説明しています。
Djangoの 400エラー処理 にフックしたい場合は、 SuspiciousOperation
例外またはそのサブクラスを発生させることができます。
ドキュメント here および here を参照してください。
あなたの例では次のようになります:
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の回答(ミドルウェアレイヤーでの例外の変換)の代わりに、ビュー関数に同じことを行うデコレーターを配置できます。個人的には私はこれを好みます。なぜなら、それは単なる古くて古いPythonであり、Djangoミドルウェアがどのように機能するかについての私の知識を払拭する必要がないからです。
意識のストリームをビュー関数のすべての機能にインライン化したくない(これにより、ビューモジュールがプロジェクトの他のすべてのモジュールに依存し、「すべてが他のすべてに依存する」アーキテクチャにつながる)代わりに、ビューの方が優れているちょうどhttpについて知っています。リクエストから必要なものを抽出し、他の「ビジネスロジック」機能に委任します。ビジネスロジックは、他のモジュール(データベースコードや他の外部システムへのインターフェイスなど)に委任する場合があります。次に、ビジネスロジックからの戻り値は、view関数によってhttp応答に変換されます。
しかし、エラーをビジネスロジック(またはそれが委任するもの)からビュー関数に戻すにはどうすればよいでしょうか。戻り値の使用は、多くの理由で厄介です。たとえば、これらのエラー戻り値は、コードベース全体を通してビューに反映されなければなりません。関数の戻り値を他の目的ですでに使用しているので、これはしばしば途方もなく厄介です。
これに対処する自然な方法は例外を使用することですが、Djangoビュー自体は、キャッチされなかった例外を返されたHTTPステータスコードに変換しません(いくつかの特別な場合を除いて、 OPは言う。)
そう。私は自分のビューに適用するデコレーターを作成します。デコレータは、発生したさまざまな例外タイプを、返された異なる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)
状況によっては、同じデコレーターがビュー関数の多く、またはすべてで機能する場合があります。
HttpResponseBadRequest を使用する準備が整いました。 実装されています as:
class HttpResponseBadRequest(HttpResponse):
status_code = 400
編集済み期日OPの質問が更新されました。
独自のヘルパーを作成して、try-catchブロックをカプセル化できます。
def myJsonDec(str):
try:
...
BadRequestを例外として発生させることで、どういう意味かわかりません。
HttpResponseの関連サブクラスを明示的に使用するか、status
パラメータを通常の応答に追加することにより、任意のステータスコードで応答を返すことができます。