#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!")