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

时间:2009-08-10 12:39:19

标签: python django rest cherrypy web-frameworks

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

我在网上找到的几个解决方案(this snippet用于基于动词的调度,或this decorator用于动词要求)不是很优雅,因为它们显然只是解决方法。

CherryPy的情况似乎是一样的。我所知道的唯一能够做到这一点的框架是web.py和Google App Engine。

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

4 个答案:

答案 0 :(得分:13)

我不能代表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试图不为你做出决定,但如果这就是你想要的话,那就很容易(单行)。

答案 1 :(得分:6)

来自Google,想到了更新。

的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!')

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

More details

的CherryPy

CherryPy现在也支持这一点。他们对此有full page

答案 2 :(得分:2)

我认为django的决定是因为通常只有GETPOST就足够了,这使得框架的要求更加简单。 “不关心”使用哪个动词非常方便。

但是,还有很多其他框架可以根据动词进行调度。我喜欢werkzeug,它可以很容易地定义您自己的调度代码,因此您可以根据自己想要的任何内容发送任何内容。

答案 3 :(得分:1)

因为这不难DIY。只需在每个班级都有一个接受动词的词典。

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