Pourquoi Django et CherryPy ne prennent-ils pas nativement en charge L'envoi par HTTP verb?

ce n'est pas la même chose de poster à une URL que de la récupérer, la supprimer ou la mettre. Ces actions sont fondamentalement différentes. Cependant, Django semble les ignorer dans son expédition mécanisme. Fondamentalement, on est forcé d'ignorer complètement les verbes HTTP ou de le faire sur chaque vue:

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'])

Les quelques solutions que j'ai trouvé pour cette dans le web (extrait pour l'expédition basée sur les verbes, ou c'décorateur pour l'exigence de verbe) ne sont pas très élégants car ils sont clairement des solutions de contournement.

la situation avec CherryPy semble être la même. Les seuls cadres que je connaisse qui font ça bien sont web.py et Google App Engine.

je vois cela comme un défaut de conception sérieux pour un framework web. Quelqu'un at-il d'accord? Ou s'agit-il d'une décision délibérée fondée sur des motifs ou des exigences que j'ignore?

12
demandé sur Martin Blech 2009-08-10 16:39:18

4 réponses

Je ne peux pas parler pour Django, mais en CherryPy, vous pouvez avoir une fonction par verbe HTTP avec une seule entrée de configuration:

request.dispatch = cherrypy.dispatch.MethodDispatcher()

Cependant, j'ai vu des situations où ce n'est pas souhaitable.

un exemple serait une redirection dure quel que soit le verbe.

un autre cas est celui où la majorité de vos manipulateurs ne manipulent que GET. Il est particulièrement ennuyeux dans ce cas d'avoir un millier de gestionnaires de page nommés 'GET'. Il est plus beau d'exprimer cela dans un décorateur que dans le nom d'une fonction:

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

un autre courant que je vois est la recherche de données correspondant à la ressource dans une base de données, qui devrait se produire indépendamment du verbe:

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 essaie de ne pas prendre la décision pour vous, mais le rend facile (un one-liner) si c'est ce que vous voulez.

13
répondu fumanchu 2009-08-10 14:22:15

J'ai trouvé ça sur Google, et j'ai pensé à mettre à jour.

Django

juste pour info, Ceci est maintenant pris en charge dans Django en tant que vues basées sur la classe. Vous pouvez étendre la classe générique View et ajouter des méthodes comme get(),post(),put() etc. E. g. -

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() partie traite de ce-

dispatch(demande, *args, **kwargs)

La vue sur une partie de la vue – la méthode qui accepte un demande d'arguments, ainsi que des arguments et retourne un De la réponse HTTP.

l'implémentation par défaut inspectera la méthode HTTP et tentera de déléguer à une méthode qui correspond à la méthode HTTP; un GET sera délégué à get(), un POST(), et ainsi de suite.

par défaut, une requête HEAD sera déléguée à get(). Si vous avez besoin de Gérer les requêtes de tête d'une manière différente de GET, vous pouvez la tête (). Voir la prise en charge D'autres HTTP méthodes pour un exemple.

l'implémentation par défaut définit aussi request, args et kwargs comme les variables d'instance, de sorte que n'importe quelle méthode sur la vue peut connaître la totalité détails de la demande présentée pour invoquer le droit d'auteur.

Ensuite, vous pouvez l'utiliser dans 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'),
)

Plus de détails.

CherryPy

CherryPy supporte maintenant aussi ceci. Ils ont un pleine page sur ce.

7
répondu Bibhas Debnath 2013-04-02 15:12:39

je crois que la décision pour django a été prise parce que d'habitude juste GET et POST est suffisant, et cela maintient le cadre plus simple pour ses exigences. Il est très pratique de "ne pas se soucier" de quel verbe a été utilisé.

cependant, il y a beaucoup d'autres cadres qui peuvent faire l'expédition basée sur le verbe. J'aime werkzeug, il rend facile de définir votre propre code d'expédition, de sorte que vous pouvez envoyer basé sur ce que vous voulez, à ce que vous voulez.

2
répondu nosklo 2009-08-10 12:46:58

parce que ce n'est pas difficile à briller. Il suffit d'avoir un dictionnaire des verbes acceptés aux fonctions dans chaque classe.

def dispatcher(someObject, request):
    try:
      return someObject.acceptedVerbs[request.method]()
    except:
      return http.HttpResponseNotAllowed(someObject.acceptedVerbs.keys())
1
répondu geowa4 2009-08-10 12:59:22