Class views in Django

前端 未结 9 1827
一生所求
一生所求 2020-12-05 06:15

Django view points to a function, which can be a problem if you want to change only a bit of functionality. Yes, I could have million keyword arguments and even more if stat

9条回答
  •  情话喂你
    2020-12-05 06:53

    I needed to use class based views, but I wanted to be able to use the full name of the class in my URLconf without always having to instantiate the view class before using it. What helped me was a surprisingly 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)
    

    I can now both instantiate view classes and use the instances as view functions, OR I can simply point my URLconf to my class and have the metaclass instantiate (and call) the view class for me. This works by checking the first argument to __call__ – if it's a HttpRequest, it must be an actual HTTP request because it would be nonsense to attept to instantiate a view 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
    
    # And all the following work as expected.
    urlpatterns = patterns(''
        url(r'^myview1$', 'myapp.views.MyView', name='myview1'),
        url(r'^myview2$', myapp.views.MyView, name='myview2'),
        url(r'^myview3$', myapp.views.MyView('foobar'), name='myview3'),
        url(r'^myotherview$', 'myapp.views.MyOtherView', name='otherview'),
    )
    

    (I posted a snippet for this at http://djangosnippets.org/snippets/2041/)

提交回复
热议问题