Http-декоратор глаголов для Django?
-
06-07-2019 - |
Вопрос
В ASP.NET MVC вы можете использовать атрибут AcceptVerbs для сопоставления функции представления с глаголом:
public ActionResult Create()
{
// do get stuff
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
// do post stuff
}
Книга Джанго предлагает что-то вроде этого:
def method_splitter(request, *args, **kwargs):
get_view = kwargs.pop('GET', None)
post_view = kwargs.pop('POST', None)
if request.method == 'GET' and get_view is not None:
return get_view(request, *args, **kwargs)
elif request.method == 'POST' and post_view is not None:
return post_view(request, *args, **kwargs)
raise Http404
URL.py:
urlpatterns = patterns('',
# ...
(r'^somepage/$', views.method_splitter, {'GET': views.some_page_get,
'POST': views.some_page_post}),
# ...
)
Мне это кажется немного некрасивым - существует ли декоратор, который может связать HTTP-глагол с представлением, в стиле ASP.NET MVC или другим общепринятым способом сделать это?
Решение
Существуют стандартные встроенные декораторы для запроса определенного метода HTTP или списка разрешенных методов.
Смотрите код: http://code.djangoproject.com/browser/django/trunk/django/views/decorators/http.py.
Другие советы
Обновленный ответ в 2016 году: В современном Django все необходимое встроено и доступно через представления на основе классов.В самой сырой форме канонический подход — это создание подклассов. django.views.generic.View
и реализация методов класса, названных в честь HTTP-глаголов:
class MyView(View):
def get(self, request, *args, **kwargs):
# ...
def post(self, request, *args, **kwargs):
# ...
Внутренне это работает очень похоже на мой древний код ниже (который был написан до того, как в Django появились представления на основе классов).Eсть View.dispatch
метод, который в основном ищет, что вызывать, или возвращает 405, если ничего не может найти: getattr(self, request.method.lower(), self.http_method_not_allowed)
.
Конечно, если вы занимаетесь обработкой форм, рендерингом шаблонов или обычными задачами CRUD, обязательно ознакомьтесь с доступными View
подклассы.
Устаревший ответ от 2009 года ниже. Код все еще работает в 2016 году, но не является решением DRY, поэтому не используйте его.В 2011 году в Django появились представления на основе классов, и в настоящее время они являются стандартным способом выполнения задач.Я храню это здесь исключительно в исторических целях.Старый текст ответа следующий:
В одном конкретном представлении, где мне нужен отдельный код для разных методов HTTP (это моя крошечная реализация WebDAV), я делаю что-то вроде этого:
class SomeView(object):
def method_get(self, request, ...):
...
def __call__(self, request, *args, **kwargs):
m = getattr(self, 'method_%s' % request.method.lower(), None)
if m is not None:
return m(request, user, *args, **kwargs)
return HttpResponseNotAllowed("405 Method Not Allowed")
# Then url(r'...', SomeView()),
Добавлено/отредактировано: Что ж, я немного подумал и реализовал подход декоратора.Это не так плохо, как я думал изначально.
def method_not_allowed_view(request, *args, **kwargs):
return HttpResponseNotAllowed("405 Method Not Allowed")
def http_method(*methods):
methods = map(lambda m: m.lower(), methods)
def __method_wrapper(f):
this_module = __import__(__name__)
chain = getattr(this_module, f.__name__, method_not_allowed_view)
base_view_func = lambda request, *args, **kwargs: \
f(request, *args, **kwargs) if request.method.lower() in methods \
else chain(request, *args, **kwargs)
setattr(this_module, f.__name__, base_view_func)
return base_view_func
return __method_wrapper
@http_method('get')
def my_view(request):
return HttpResponse("Thank you for GETting.")
@http_method('post', 'put')
def my_view(request):
return HttpResponse("Thank you for POSTing or PUTting.")
# url(r'...', 'app.my_view'),
В любом случае, этот пост является вики-сообществом, так что не стесняйтесь улучшать его, если вам нравится эта идея!И история изменений также содержит несколько разных подходов, которые я пробовал, прежде чем писать это...
Вы можете использовать Посмотреть декораторы
Из документов:
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET", "POST"])
def my_view(request):
# I can assume now that only GET or POST requests make it this far
# ...
pass