Почему Django и CherryPy изначально не поддерживают отправку на основе глаголов HTTP? - PullRequest
12 голосов
/ 10 августа 2009

Это не то же самое, что POST для URL, чем для его получения, DELETE или PUT. Эти действия принципиально разные. Тем не менее, Джанго, кажется, игнорирует их в своем механизме отправки. По сути, каждый вынужден либо полностью игнорировать 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.

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

Ответы [ 4 ]

13 голосов
/ 10 августа 2009

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

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 пытается не принимать решение за вас, но упрощает (однострочно), если вы этого хотите.

6 голосов
/ 31 марта 2013

Наткнулся на это от Google, и думал об обновлении.

Джанго

Просто к сведению, теперь это поддерживается в 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.

Реализация по умолчанию также устанавливает request, 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 теперь также поддерживает это. У них есть полная страница на этом.

2 голосов
/ 10 августа 2009

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

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

1 голос
/ 10 августа 2009

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

def dispatcher(someObject, request):
    try:
      return someObject.acceptedVerbs[request.method]()
    except:
      return http.HttpResponseNotAllowed(someObject.acceptedVerbs.keys())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...