Почему Django и CherryPy не поддерживают HTTP-глагол?

Это не то же самое для POST для URL-адреса, кроме как для его получения, УДАЛИТЬ его или ОТКЛЮЧИТЬ. Эти действия коренным образом отличаются. Тем не менее, Django, кажется, игнорирует их в своем диспетчерском механизме. В принципе, каждый вынужден либо полностью игнорировать глаголы HTTP, либо делать это во всех представлениях:

def my_view(request, arg1, arg2):
    if request.method == 'GET':
        return get_view(request, arg1, arg2)
    if request.method == 'POST':
        return post_view(request, arg1, arg2)
    return http.HttpResponseNotAllowed(['GET', 'POST'])

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

Ситуация с CherryPy кажется одинаковой. Единственные рамки, которые я знаю об этом, - это web.py и Google App Engine.

Я рассматриваю это как серьезный недостаток дизайна для веб-фреймворка. Кто-нибудь согласен? Или это намеренное решение, основанное на причинах/требованиях, которые я игнорирую?

Ответ 1

Я не могу говорить за Django, но в CherryPy у вас может быть одна функция для HTTP-глагола с одной записью config:

request.dispatch = cherrypy.dispatch.MethodDispatcher()

Однако я видел некоторые ситуации, когда это нежелательно.

Одним из примеров может быть жесткое перенаправление независимо от глагола.

Другим случаем является то, что большинство обработчиков обрабатывают только GET. Особенно раздражает в этом случае иметь тысячи обработчиков страниц, все из которых называются GET. Лучше выразить это в декораторе, чем в имени функции:

def allow(*methods):
    methods = list(methods)
    if not methods:
        methods = ['GET', 'HEAD']
    elif 'GET' in methods and 'HEAD' not in methods:
        methods.append('HEAD')
    def wrap(f):
        def inner(*args, **kwargs):
            cherrypy.response.headers['Allow'] = ', '.join(methods)
            if cherrypy.request.method not in methods:
                raise cherrypy.HTTPError(405)
            return f(*args, **kwargs):
        inner.exposed = True
        return inner
    return wrap

class Root:
    @allow()
    def index(self):
        return "Hello"

    cowboy_greeting = "Howdy"

    @allow()
    def cowboy(self):
        return self.cowboy_greeting

    @allow('PUT')
    def cowboyup(self, new_greeting=None):
        self.cowboy_greeting = new_greeting

Другой распространенный, который я вижу, - это поиск данных, соответствующих ресурсу в базе данных, который должен происходить независимо от глагола:

def default(self, id, **kwargs):
    # 404 if no such beast
    thing = Things.get(id=id)
    if thing is None:
        raise cherrypy.NotFound()

    # ...and now switch on method
    if cherrypy.request.method == 'GET': ...

CherryPy пытается не принять решение для вас, но делает его легким (однострочным), если это то, что вы хотите.

Ответ 2

Перешел через это от Google, и подумал об обновлении.

Джанго

Просто FYI, теперь это поддерживается в Django как класс. Вы можете расширить общий класс View и добавить такие методы, как get(), post(), put() и т.д. -

from django.http import HttpResponse
from django.views.generic import View

class MyView(View):

    def get(self, request, *args, **kwargs):
        return HttpResponse('Hello, World!')

Элемент dispatch() обрабатывает это:

отправка (запрос, * args, ** kwargs)

Представленная часть представления - метод, который принимает аргумент запроса плюс аргументы и возвращает HTTP-ответ.

Реализация по умолчанию проверяет метод HTTP и пытается делегировать метод, соответствующий методу HTTP; GET будет делегированы для получения(), POST для post() и т.д.

По умолчанию запрос HEAD будет делегирован get(). Если вам нужно обрабатывать запросы HEAD иначе, чем GET, вы можете переопределить head(). См. Поддержка других HTTP-методов для примера.

Реализация по умолчанию также задает запрос, args и kwargs как переменные экземпляра, поэтому любой метод на представлении может знать полный подробности запроса, который был сделан для вызова представления.

Затем вы можете использовать его в urls.py -

from django.conf.urls import patterns, url

from myapp.views import MyView

urlpatterns = patterns('',
    url(r'^mine/$', MyView.as_view(), name='my-view'),
)

Подробнее.

CherryPy

Теперь CherryPy поддерживает это. У них есть полная страница.

Ответ 3

Я считаю, что решение для django было сделано, потому что обычно просто GET и POST достаточно, и это упрощает структуру для своих требований. Очень удобно просто "не заботиться" о том, какой глагол использовался.

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

Ответ 4

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

def dispatcher(someObject, request):
    try:
      return someObject.acceptedVerbs[request.method]()
    except:
      return http.HttpResponseNotAllowed(someObject.acceptedVerbs.keys())