Awkwardness of overriding View.dispatch for method-agnostic request-handling

737 views
Skip to first unread message

Alexander Dutton

unread,
Apr 10, 2012, 9:44:42 AM4/10/12
to Django developers
Hi all,

[I think this has been mentioned on django-developers before, but I
can't find it. If this would be better as an RFE in a ticket, shout at
me and I'll raise it there.]

In a couple of our projects we have various views on resources
differentiated by some aspect of the request (query parameters, whether
it's WebDAV, etc).

In these cases, we have something that looks like:

class DAVView(View): …

class BrowserView(View): …

class IndexView(View):
# Use staticmethod as we get a function back from as_view()
dav_view = staticmethod(DAVView.as_view())
browser_view = staticmethod(BrowserView.as_view())

def dispatch(self, request, path):
view = self.dav_view if self.is_dav(request) else self.browser_view
return view(request, path)

This is fine, until we want to inherit functionality provided by other
overridings of dispatch(). For example, we might have a View sub-class
that checks that the user has permission to access the given path. We'd
have to do weird things to get the MRO right, when we really just want
to override the bit in View.dispatch that dispatches to a HTTP
method-specific handler.

There are other instances where one might want to provide a
method-agnostic handler without overriding the entirety of the
dispatch() chain.

Can we therefore split View.dispatch in two?:

def dispatch(self, request, *args, **kwargs):
self.request = request
self.args = args
self.kwargs = kwargs
return self.handle(request, *args, **kwargs)

def handle(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)

This allows people like me to override the bit at the bottom relatively
cleanly.

All the best,

Alex

schinckel

unread,
Apr 11, 2012, 2:12:51 AM4/11/12
to django-d...@googlegroups.com
I agree: but this means that the actual dispatcher (that, according to the comments,
"dispatch[es] to the right method", is called handle(), rather than dispatch.

Perhaps the assignation of request/args/kwargs could happen before dispatch is 
called?

Meshy

unread,
Apr 11, 2012, 7:05:26 AM4/11/12
to django-d...@googlegroups.com
I agree that there is a need for this -- it has come up several times for me now -- however, I prefer my proposal (pretty printed here: https://gist.github.com/1957251 , code below...) mentioned in the topic "Class based views: A standard hook for http-method-independent code" (https://groups.google.com/d/topic/django-developers/7c7aI-slGNc/discussion).

Instead of separating the handler, I proposed a prepare_view method.

    def dispatch(self, request, *args, **kwargs):
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        self.prepare_view(request, handler, *args, **kwargs)
        return handler(request, *args, **kwargs)

    def prepare_view(self, request, handler, *args, **kwargs):
        """Set local variables before the dispatch handler is called."""
        self.request = request
        self.args = args
        self.kwargs = kwargs

Reply all
Reply to author
Forward
0 new messages