I needed to use class-based views, but I wanted to be able to use the fully qualified class name in my URLconf, without having to create an instance of the view class before using it. What helped me was an amazingly simple metaclass:
class CallableViewClass(type): def __call__(cls, *args, **kwargs): if args and isinstance(args[0], HttpRequest): instance = super(CallableViewClass, cls).__call__() return instance.__call__(*args, **kwargs) else: instance = super(CallableViewClass, cls).__call__(*args, **kwargs) return instance class View(object): __metaclass__ = CallableViewClass def __call__(self, request, *args, **kwargs): if hasattr(self, request.method): handler = getattr(self, request.method) if hasattr(handler, '__call__'): return handler(request, *args, **kwargs) return HttpResponseBadRequest('Method Not Allowed', status=405)
Now I can both create instances of class classes and use instances as view functions. OR I can just point my URLconf to my class and create a metaclass (and call) a view class for me. This works by checking the first argument for __call__ - if it is a HttpRequest , it should be the actual HTTP request, because it would be pointless to try to create an instance of the class with an HttpRequest instance.
class MyView(View): def __init__(self, arg=None): self.arg = arg def GET(request): return HttpResponse(self.arg or 'no args provided') @login_required class MyOtherView(View): def POST(request): pass
(I posted a snippet for this at http://djangosnippets.org/snippets/2041/ )
Erik Allik May 27 '10 at 13:02 2010-05-27 13:02
source share