为什么Django和CherryPy本身不支持基于HTTP动词的调度?

Mar*_*ech 12 python django rest web-frameworks cherrypy

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'])
Run Code Online (Sandbox Code Playgroud)

我在网上找到的几个解决方案(基于动词的调度的这个片段,或动词要求的这个装饰器)不是很优雅,因为它们显然只是解决方法.

CherryPy的情况似乎是一样的.我所知道的唯一正确的框架是web.py和Google App Engine.

我认为这是Web框架的一个严重的设计缺陷.有人同意吗?或者这是基于我忽略的原因/要求的故意决定?

fum*_*chu 13

我不能代表Django,但在CherryPy中,每个HTTP动词可以有一个函数,只有一个配置条目:

request.dispatch = cherrypy.dispatch.MethodDispatcher()
Run Code Online (Sandbox Code Playgroud)

但是,我已经看到了一些不可取的情况.

一个例子是硬重定向而不管动词.

另一种情况是大多数处理程序只处理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
Run Code Online (Sandbox Code Playgroud)

我看到的另一个常见的是查找与数据库中的资源相对应的数据,无论动词如何都应该发生:

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': ...
Run Code Online (Sandbox Code Playgroud)

CherryPy试图不为你做出决定,但如果那就是你想要的话,那就很容易(单行).


Bib*_*ath 6

从谷歌那里得到了这个,并想到了更新.

Django的

仅供参考,现在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!')
Run Code Online (Sandbox Code Playgroud)

dispatch()部分处理这个 -

派遣(请求,*args,**kwargs)

视图的视图部分 - 接受请求参数和参数的方法,并返回HTTP响应.

默认实现将检查HTTP方法并尝试委托给与HTTP方法匹配的方法; 一个GET将被委托给get(),一个POST到post(),依此类推.

默认情况下,HEAD请求将委派给get().如果需要以与GET不同的方式处理HEAD请求,则可以覆盖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'),
)
Run Code Online (Sandbox Code Playgroud)

更多细节.

CherryPy的

CherryPy现在也支持这一点.他们有一整页.


nos*_*klo 2

我相信 django 的决定是因为通常就GET足够POST了,并且这使得框架更简单地满足其要求。“不关心”使用哪个动词是非常方便的。

然而,还有很多其他框架可以基于动词进行调度。我喜欢werkzeug,它可以轻松定义您自己的调度代码,因此您可以根据您想要的任何内容进行调度。

  • 尽管通常 GET 和 POST 就足够了,但动词的数量不是这里的问题。我只是想不出控制器(在 Django 中称为“视图”)应该对 GET 和 POST 执行完全相同的操作的单一用例。 (4认同)
  • @nosklo:因为它们根本不是同一件事。可以安全地忽略动词的情况非常奇怪(我仍然没有看到一个)。因此,这些框架将最不常见的情况(动词无关紧要)设为默认值,并将最常见的情况(动词重要)设为可选的非标准化功能。我认为应该是相反的。 (3认同)
  • @马丁:为什么不呢?他们是同一件事。您可以轻松编写一个“不关心”请求是作为 get 还是作为 post 的应用程序。 (2认同)