django: поднять BadRequest как исключение?

можно ли поднять BadRequest как исключение в django?

Я видел, что вы можете поднять 404 [1].

вариант использования: в вспомогательном методе я загружаю json из запроса.ПОЛУЧИТЬ. Если json был вырезан, так как браузер (IE) вырезал url-адрес, я хотел бы вызвать соответствующее исключение.

исключение BadRequest выглядит подходящим, но до сих пор в django нет такого исключения.

в 1.6 есть исключения SuspiciousOperation. Но это не соответствует в моем случае, так как это не связано с безопасностью.

конечно, я мог бы попробовать..за исключением моего вспомогательного метода в методе view, но это не сухо.

у кого-то есть решение, где мне не нужно пытаться..исключение вокруг каждого вызова моего метода helper?

[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

5 ответов


вам нужно пользовательское промежуточное ПО для обработки исключения, которое вы поднимаете. Вам нужно иметь пользовательские исключения, чтобы проверить его в 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")

другие ответы объясняют, как вернуть HTTP-ответ со статусом 400.

Если вы хотите подключиться к Django's 400 обработка ошибок, вы можете поднять SuspiciousOperation исключение или подкласс этого.

посмотреть документы здесь и здесь.

в вашем примере это будет выглядеть так:

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

HttpResponseBadRequest готово к использованию. это реализовано as:

class HttpResponseBadRequest(HttpResponse):
    status_code = 400

редактировать из-за обновленного вопроса OP.

Вы можете создать свой собственный помощник и инкапсулировать в него блок try-catch.

def myJsonDec(str):
    try:
        ...

в качестве альтернативы ответу @coldmind (преобразование исключений в промежуточном слое) вы можете поместить декоратор в свою функцию представления, которая делает то же самое. Лично я предпочитаю это, потому что это просто старый Python, и не требует от меня пыли от моих знаний о том, как работает промежуточное ПО Django.

вы не хотите, чтобы stream-of-conciousness встроил все функции в функции просмотра (это делает ваш модуль просмотра зависимым от всех других модулей вашего проекта, ведущих для архитектуры "все зависит от всего остального") вместо этого лучше, если представление просто знает о http. Он извлекает то, что вам нужно из запроса, делегирует некоторую другую функцию "бизнес-логики". Бизнес-логика может делегироваться другим модулям (например, коду базы данных или интерфейсам других внешних систем).) Затем, наконец, возвращаемое значение из вашей бизнес-логики преобразуется в http-ответ функцией view.

но как передать ошибки обратно в представление функция из бизнес-логики (или что она делегирует)? Использование возвращаемых значений раздражает по многим причинам. Например, эти возвращаемые значения ошибок должны быть возвращены в представление из всей вашей кодовой базы. Это часто калечит, потому что вы уже будете использовать возвращаемые значения функций для других целей.

естественный способ справиться с этим-использовать исключения, но представление 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)

в зависимости от обстоятельств, вы можете обнаружить, что один и тот же декоратор может работать на многих или всех ваших функциях просмотра.


Я не уверен, что вы имеете в виду, поднимая BadRequest как исключение.

вы можете вернуть ответ с любым кодом состояния, который вам нравится, либо явно используя соответствующий подкласс HttpResponse, либо добавив status параметр к нормальному ответу.