12

POST 到 URL 与 GET、DELETE 或 PUT 不同。这些行动是根本不同的。然而,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 的。

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

4

4 回答 4

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 试图不为您做出决定,但如果您想要的话,它会变得容易(单行)。

于 2009-08-10T14:22:15.733 回答
6

从谷歌看到这个,并想到更新。

姜戈

仅供参考,现在 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'),
)

更多细节

樱桃派

CherryPy 现在也支持这一点。他们有一个完整的页面

于 2013-03-31T10:35:44.737 回答
2

我相信 django 的决定是因为通常只是GETPOST了,这使得框架更简单地满足其要求。只“不在乎”使用哪个动词非常方便。

但是,还有很多其他框架可以基于动词进行调度。我喜欢werkzeug,它可以很容易地定义你自己的调度代码,所以你可以根据你想要的任何东西来调度任何你想要的东西。

于 2009-08-10T12:46:58.937 回答
1

因为这并不难DIY。只需有一本接受动词的字典即可在每个类中使用。

def dispatcher(someObject, request):
    try:
      return someObject.acceptedVerbs[request.method]()
    except:
      return http.HttpResponseNotAllowed(someObject.acceptedVerbs.keys())
于 2009-08-10T12:58:12.980 回答