13👍
I can’t speak for Django, but in CherryPy, you can have one function per HTTP verb with a single config entry:
request.dispatch = cherrypy.dispatch.MethodDispatcher()
However, I have seen some situations where that’s not desirable.
One example would be a hard redirect regardless of verb.
Another case is when the majority of your handlers only handle GET. It’s especially annoying in that case to have a thousand page handlers all named ‘GET’. It’s prettier to express that in a decorator than in a function name:
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
Another common one I see is looking up data corresponding to the resource in a database, which should happen regardless of verb:
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 tries to not make the decision for you, yet makes it easy (a one-liner) if that’s what you want.
6👍
Came across this from Google, and thought of updating.
Django
Just FYI, This is now supported in Django as class based views. You can extend the generic class View
and add methods like 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!')
The dispatch()
part handles this-
dispatch(request, *args, **kwargs)
The view part of the view – the
method that accepts a request argument plus arguments, and returns a
HTTP response.The default implementation will inspect the HTTP method and attempt to
delegate to a method that matches the HTTP method; a GET will be
delegated to get(), a POST to post(), and so on.By default, a HEAD request will be delegated to get(). If you need to
handle HEAD requests in a different way than GET, you can override the
head() method. See Supporting other HTTP methods for an example.The default implementation also sets request, args and kwargs as
instance variables, so any method on the view can know the full
details of the request that was made to invoke the view.
Then you can use it in 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 now also supports this. They have a full page on this.
- Determine if Django is running under the development server
- Programmatically sync the db in Django
- How can I create a partial search filter in Django REST framework?
- Celerybeat automatically disables periodic task
- Django datefield and timefield to python datetime
2👍
I believe the decision for django was made because usually just GET
and POST
is enough, and that keeps the framework simpler for its requirements. It is very convenient to just “not care” about which verb was used.
However, there are plenty other frameworks that can do dispatch based on verb. I like werkzeug, it makes easy to define your own dispatch code, so you can dispatch based on whatever you want, to whatever you want.
- Celery: launch task on start
- How to get django queryset results with formatted datetime field
- Determine if Django is running under the development server
- How to connect PyCharm to a Heroku postgres database
- Django no module named "compressor"
1👍
Because this is not hard to DIY. Just have a dictionary of accepted verbs to functions in each class.
def dispatcher(someObject, request):
try:
return someObject.acceptedVerbs[request.method]()
except:
return http.HttpResponseNotAllowed(someObject.acceptedVerbs.keys())