Django: просмотры и утверждения, подобные возвратам

#python #django #assert

#python #django #утверждать

Вопрос:

Интересно, существует ли хакерский способ python для достижения следующего:

Я обнаружил, что часто использую структуру, подобную утверждению, в своих представлениях:

 def view(request):
    if not condition:
        return HttpResponseServerError("error")

    if not condition2:
        return HttpResponseServerError("error2")

    [...]

    return HttpResponse("OK!")
  

Итак, я подумал об использовании функции, подобной утверждению:

 def view(request):
    def err(msg=None):
        msg = msg if msg else "Illegal Parameters"
        resp = {"msg": msg}
        resp = json.dumps(resp)
        return HttpResponseServerError(resp)

    def verify(exp, msg=None):
        if not exp:
            err(msg)

    verify(condition, "error")

    verify(condition2, "error2")

    return HttpResponse("OK")
  

Очевидно, что это не работает, поскольку результат функции error никогда не возвращается. Кроме того, мне также нужно было бы полностью вернуть ответ в функцию просмотра и выполнить return verify() , что, конечно, предотвратит выполнение моего кода.

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

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

Но в этом посте я действительно ищу более хакерский способ, позволяющий вложенной функции возвращать ответ вместо родительской функции и, следовательно, предотвращать выполнение.

Я опубликую свое «решение» yield в отдельном ответе, чтобы вы могли получить представление 🙂

Комментарии:

1. Почему не исключения? Я думаю, что так get_object_or_404() реализовано, например.

2. Сейчас мне хочется ударить себя палкой…

3. @rodrigo Однако, если вы создаете исключение, это ограничивает ваши возможности, если вы его не поймаете (возможно, в декораторе xP). Если я хочу вернуть правильный ответ JSON, который просто содержит error: True , например.

4. Да, если вы хотите сделать это более чем в одном представлении, декоратор — это правильный путь. Если это только одно представление, оно того не стоит.

5. Здесь я добавил ответ, содержащий все вместе взятые. Я не тестировал это, поэтому воспринимайте это как набросок.

Ответ №1:

Как насчет исключения и хорошего декоратора для его перехвата:

 class AssertError(Exception):
    pass

def assertLike(view):
    def wrap(request, *args, **kwargs):
        try:
            return view(request, *args, **kwargs):
        except AssertError as e:
            return HttpResponseServerError(...)
    return wrap

@assertLike
def createTask(request):
    import json
    ....
    if not exp:
        raise AssertError()
    ....
    return HttpResponse("Ok")
  

Комментарии:

1. Мне действительно нравится идея. Лучше, чем у меня, поскольку это очищает синтаксис от частого использования yield. Я рассматриваю возможность реализации этого в модуле с надлежащим исключением, которое позволяет передавать ответы!

Ответ №2:

Здесь я представляю решение на основе генератора:

 def assertLike(view):
    def wrap(request, *args, **kwargs):
        for response in view(request, *args, **kwargs):
            if response:
                return response
    return wrap


@other_django_views
@another_django_view
@assertLike
def createTask(request):
    import json

    def err(msg=None):
        msg = msg if msg else "Illegal Parameters"
        resp = {"msg": msg}
        resp = json.dumps(resp)
        return HttpResponseServerError(resp)

    def verify(exp, msg=None):
        if not exp:
            return err(msg)

    # only react to ajax requests
    yield verify(True, "This is not an error")
    yield verify(False, "Here it should stop!")

    yield HttpResponse("This is the final response!")