Skip to content

Instantly share code, notes, and snippets.

@gsakkis
Created October 17, 2010 21:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gsakkis/631306 to your computer and use it in GitHub Desktop.
Save gsakkis/631306 to your computer and use it in GitHub Desktop.
Replace classmethod with descriptor
diff --git a/django/views/generic/base.py b/django/views/generic/base.py
--- a/django/views/generic/base.py
+++ b/django/views/generic/base.py
@@ -9,6 +9,39 @@
logger = getLogger('django.request')
+class AsViewDescriptor(object):
+ def __get__(self, instance, cls):
+ if instance is not None:
+ raise TypeError(u"You tried to call 'as_view()' on a View instance "
+ u"instead of a View (sub)class")
+ def as_view(*initargs, **initkwargs):
+ """
+ Main entry point for a request-response process.
+ """
+ # sanitize keyword arguments
+ for key in initkwargs:
+ if key in cls.method_names:
+ raise TypeError(u"You tried to pass in the %s method name as a "
+ u"keyword argument to %s(). Don't do that."
+ % (key, cls.__name__))
+ if not hasattr(cls, key):
+ raise TypeError(u"%s() received an invalid keyword %r" % (
+ cls.__name__, key))
+
+ def view(request, *args, **kwargs):
+ self = cls(*initargs, **initkwargs)
+ return self.dispatch(request, *args, **kwargs)
+
+ # take name and docstring from class
+ update_wrapper(view, cls, updated=())
+
+ # and possible attributes set by decorators
+ # like csrf_exempt from dispatch
+ update_wrapper(view, cls.dispatch, assigned=())
+ return view
+ return as_view
+
+
class View(object):
"""
Intentionally simple parent class for all views. Only implements
@@ -17,6 +50,8 @@
method_names = ['get', 'post', 'put', 'delete', 'head', 'options', 'trace']
+ as_view = AsViewDescriptor()
+
def __init__(self, *args, **kwargs):
"""
Constructor. Called in the URLconf; can contain helpful extra
@@ -27,33 +62,6 @@
for key, value in kwargs.iteritems():
setattr(self, key, value)
- @classmethod
- def as_view(cls, *initargs, **initkwargs):
- """
- Main entry point for a request-response process.
- """
- # sanitize keyword arguments
- for key in initkwargs:
- if key in cls.method_names:
- raise TypeError(u"You tried to pass in the %s method name as a "
- u"keyword argument to %s(). Don't do that."
- % (key, cls.__name__))
- if not hasattr(cls, key):
- raise TypeError(u"%s() received an invalid keyword %r" % (
- cls.__name__, key))
-
- def view(request, *args, **kwargs):
- self = cls(*initargs, **initkwargs)
- return self.dispatch(request, *args, **kwargs)
-
- # take name and docstring from class
- update_wrapper(view, cls, updated=())
-
- # and possible attributes set by decorators
- # like csrf_exempt from dispatch
- update_wrapper(view, cls.dispatch, assigned=())
- return view
-
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method for that; if it doesn't exist,
# raise a big error.
diff --git a/tests/regressiontests/generic_views/base.py b/tests/regressiontests/generic_views/base.py
--- a/tests/regressiontests/generic_views/base.py
+++ b/tests/regressiontests/generic_views/base.py
@@ -82,6 +82,12 @@
self.rf.get('/', REQUEST_METHOD='FAKE')
).status_code, 405)
+ def test_instance_as_view(self):
+ """
+ Test that 'as_view' can be called only from a View class, not instance.
+ """
+ self.assertRaises(TypeError, getattr, CustomizableView(parameter="value"), "as_view")
+
def test_invalid_keyword_argument(self):
"""
Test that view arguments must be predefined on the class and can't
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment