クラスベースのビューを使用する必要がありましたが、ビュークラスを使用する前に常にインスタンス化することなく、URLconf でクラスの完全な名前を使用できるようにしたいと考えていました。私を助けたのは、驚くほど単純なメタクラスでした。
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)
これで、ビュー クラスをインスタンス化し、そのインスタンスをビュー関数として使用できます。または、単に URLconf を自分のクラスに向けて、メタクラスにビュー クラスをインスタンス化 (および呼び出し) させることもできます。これは、最初の引数をチェックすることで機能します。それが である__call__
場合HttpRequest
は、実際の HTTP リクエストでなければなりません。インスタンスを使用してビュー クラスをインスタンス化しようとするのはナンセンスだからHttpRequest
です。
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'),
)
(これのスニペットをhttp://djangosnippets.org/snippets/2041/に投稿しました)