Permalink
Browse files

Massive refactoring with view that can only be instatiated once. Only…

… the base view works.
  • Loading branch information...
bfirsh committed May 29, 2010
1 parent 0816ad5 commit 5424e16be645e08ab9614e40982233b1584a3412
View
@@ -1,52 +1,117 @@
+from django import http
+from django.core import serializers
from django.core.exceptions import ImproperlyConfigured
-from django.http import HttpResponse, HttpResponseNotAllowed
from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _
class View(object):
"""
Parent class for all views.
"""
-
- def __init__(self, **kwargs):
- self._load_config_values(kwargs,
- context_processors = None,
- mimetype = 'text/html',
- template_loader = None,
- template_name = None,
- decorators = None,
- )
- if kwargs:
- raise TypeError("__init__() got an unexpected keyword argument '%s'" % iter(kwargs).next())
-
+
+ template_name = None
+ context_processors = None
+ template_loader = None
+ decorators = None
+ allowed_methods = ['GET', 'POST']
+ strict_allowed_methods = False
+ allowed_formats = ['html']
+ format_mimetypes = {
+ 'html': 'text/html'
+ }
+ default_format = 'html'
+
+ def __init__(self, *args, **kwargs):
+ self._has_been_called = False
+ super(View, self).__init__(*args, **kwargs)
+
def __call__(self, request, *args, **kwargs):
- method = getattr(self, request.method.lower(), 'get')
- if self.decorators is not None:
- for decorator in reversed(self.decorators):
- method = decorator(method)
- return method(request, *args, **kwargs)
+ self._check_has_been_called()
+ self.request = request
+ callback = self.get_callback()
+ if callback:
+ return callback(*args, **kwargs)
+ allowed_methods = [m for m in self.allowed_methods if hasattr(self, m)]
+ return http.HttpResponseNotAllowed(allowed_methods)
+
+ def get_callback(self):
+ """
+ Based on the request's HTTP method, get the callback on this class that
+ returns a response. If the method isn't allowed, None is returned.
+ """
+ method = self.request.method.upper()
+ if method not in self.allowed_methods:
+ if self.strict_allowed_methods:
+ return None
+ else:
+ method = 'GET'
+ callback = getattr(self, method, getattr(self, 'GET', None))
+ if callback:
+ if self.decorators is not None:
+ for decorator in self.decorators:
+ callback = decorator(callback)
+ return callback
+
+ def GET(self, *args, **kwargs):
+ content = self.get_content(*args, **kwargs)
+ mimetype = self.get_mimetype()
+ return self.get_response(content, mimetype=mimetype)
+
+ def get_response(self, content, **httpresponse_kwargs):
+ """
+ Construct an `HttpResponse` object.
+ """
+ return http.HttpResponse(content, **httpresponse_kwargs)
- def get(self, request, *args, **kwargs):
- obj = self.get_object(request, *args, **kwargs)
- template = self.get_template(request, obj)
- context = self.get_context(request, obj)
- mimetype = self.get_mimetype(request, obj)
- response = self.get_response(request, obj, template, context, mimetype=mimetype)
- return response
+ def get_content(self):
+ """
+ Get the content to go in the response.
+ """
+ format = self.get_format()
+ resource = self.get_resource()
+ return getattr(self, 'render_%s' % format)(resource)
- def get_object(self, request, *args, **kwargs):
- return None
+ def get_resource(self, *args, **kwargs):
+ """
+ Get a dictionary representing the resource for this view.
+ """
+ return {}
- def get_template(self, request, obj):
+ def get_mimetype(self):
+ """
+ Get the mimetype to be used for the response.
+ """
+ return self.format_mimetypes[self.get_format()]
+
+ def get_format(self):
+ """
+ Get the format for the content, defaulting to ``default_format``.
+
+ The format is usually a short string to identify the format of the
+ content in the response. For example, 'html' or 'json'.
+ """
+ format = self.request.GET.get('format', self.default_format)
+ if format not in self.allowed_formats:
+ format = self.default_format
+ return format
+
+ def render_html(self, resource):
+ """
+ Render a template with a given resource
+ """
+ return self.get_template().render(self.get_context())
+
+ def get_template(self):
"""
Get a ``Template`` object for the given request.
"""
- names = self.get_template_names(request, obj)
+ names = self.get_template_names()
if not names:
- raise ImproperlyConfigured("'%s' must provide template_name." % self.__class__.__name__)
- return self.load_template(request, obj, names)
+ raise ImproperlyConfigured("'%s' must provide template_name."
+ % self.__class__.__name__)
+ return self.load_template(names)
- def get_template_names(self, request, obj):
+ def get_template_names(self):
"""
Return a list of template names to be used for the request. Must return
a list. May not be called if get_template is overridden.
@@ -58,54 +123,40 @@ def get_template_names(self, request, obj):
else:
return self.template_name
- def load_template(self, request, obj, names=[]):
+ def load_template(self, names=[]):
"""
Load a template, using self.template_loader or the default.
"""
- return self.get_template_loader(request, obj).select_template(names)
+ return self.get_template_loader().select_template(names)
- def get_template_loader(self, request, obj):
+ def get_template_loader(self):
"""
Get the template loader to be used for this request. Defaults to
``django.template.loader``.
"""
import django.template.loader
return self.template_loader or django.template.loader
- def get_context(self, request, obj, context=None):
+ def get_context(self, *args, **kwargs):
"""
- Get the context. Must return a Context (or subclass) instance.
+ Get the template context. Must return a Context (or subclass) instance.
"""
- processors = self.get_context_processors(request, obj)
- if context is None:
- context = {}
- return RequestContext(request, context, processors)
+ resource = self.get_resource(*args, **kwargs)
+ context_processors = self.get_context_processors()
+ return RequestContext(self.request, resource, context_processors)
- def get_context_processors(self, request, obj):
+ def get_context_processors(self):
"""
- Get the context processors to be used for the given request.
+ Get the template context processors to be used.
"""
return self.context_processors
- def get_mimetype(self, request, obj):
- """
- Get the mimetype to be used for the given request.
- """
- return self.mimetype
-
- def get_response(self, request, obj, template, context, **httpresponse_kwargs):
- """
- Construct an `HttpResponse` object given the template and context.
- """
- return HttpResponse(template.render(context), **httpresponse_kwargs)
-
- def _load_config_values(self, initkwargs, **defaults):
- """
- Set on self some config values possibly taken from __init__, or
- attributes on self.__class__, or some default.
- """
- for k in defaults:
- default = getattr(self.__class__, k, defaults[k])
- value = initkwargs.pop(k, default)
- setattr(self, k, value)
+ def _check_has_been_called(self):
+ if self._has_been_called:
+ raise ImproperlyConfigured("'%(class)s' has been instantiated in "
+ "the URLconf. Class-based views should only be passed as "
+ "classes. Try changing '%(class)s()' to '%(class)s'." % {
+ 'class': self.__class__.__name__
+ })
+ self._has_been_called = True
@@ -10,15 +10,11 @@ class DetailView(View):
By default this is a model instance lookedup from `self.queryset`, but the
view will support display of *any* object by overriding `get_object()`.
"""
-
- def __init__(self, **kwargs):
- self._load_config_values(kwargs,
- queryset = None,
- slug_field = 'slug',
- template_object_name = None,
- template_name_field = None,
- )
- super(DetailView, self).__init__(**kwargs)
+
+ queryset = None
+ slug_field = 'slug'
+ template_object_name = None
+ template_name_field = None
def get_object(self, request, pk=None, slug=None, object_id=None, queryset=None):
"""
@@ -2,7 +2,7 @@
from class_based_views import View, ListView, DetailView
class FormView(View):
- def post(self, request, *args, **kwargs):
+ def POST(self, request, *args, **kwargs):
obj = self.get_object(request, *args, **kwargs)
form = self.get_form(request, obj, *args, **kwargs)
if form.is_valid():
View
@@ -10,18 +10,14 @@ class ListView(View):
`self.items`, but if it's a queryset set on `self.queryset` then the
queryset will be handled correctly.
"""
-
- def __init__(self, **kwargs):
- self._load_config_values(kwargs,
- paginate_by = None,
- allow_empty = True,
- template_object_name = None,
- queryset = None,
- items = None,
- )
- super(ListView, self).__init__(**kwargs)
-
- def get(self, request, *args, **kwargs):
+
+ paginate_by = None
+ allow_empty = True
+ template_object_name = None
+ queryset = None
+ items = None
+
+ def GET(self, request, *args, **kwargs):
page = kwargs.get('page', None)
paginator, page, items = self.get_items(request, page)
template = self.get_template(request, items)
@@ -40,7 +36,7 @@ def get_items(self, request, page):
elif hasattr(self, 'items') and self.items is not None:
items = self.items
else:
- raise ImproperlyConfigured("'%s' must define 'queryset' or 'items'" \
+ raise ImproperlyConfigured("'%s' must define 'queryset' or 'items'"
% self.__class__.__name__)
return self.paginate_items(request, items, page)
@@ -118,21 +114,6 @@ def get_context(self, request, items, paginator, page, context=None):
template_obj_name = self.get_template_object_name(request, items)
if template_obj_name:
context[template_obj_name] = items
-
- # If we're paginated, populate the context with legacy pagination
- # stuff. In 1.2 `legacy_context` will default to False, and in 1.3
- # these context variables will be removed.
- if paginator is not None and getattr(self, 'legacy_context', True):
- import warnings
- warnings.warn(
- "'%(cls)s' is using legacy context variables which will be "\
- "removed in a future version of Django. Set "\
- "'%(cls)s.legacy_content' to False to stop using these "\
- "context variables." % {'cls': self.__class__.__name__},
- PendingDeprecationWarning
- )
- context.update(self._get_legacy_paginated_context(paginator, page))
-
return context
def get_template_object_name(self, request, items):
@@ -145,23 +126,4 @@ def get_template_object_name(self, request, items):
return smart_str(items.model._meta.verbose_name_plural)
else:
return None
-
- def _get_legacy_paginated_context(self, paginator, page):
- """
- Legacy template context stuff. New templates should use page_obj
- to access this instead.
- """
- return {
- 'is_paginated': page.has_other_pages(),
- 'results_per_page': paginator.per_page,
- 'has_next': page.has_next(),
- 'has_previous': page.has_previous(),
- 'page': page.number,
- 'next': page.next_page_number(),
- 'previous': page.previous_page_number(),
- 'first_on_page': page.start_index(),
- 'last_on_page': page.end_index(),
- 'pages': paginator.num_pages,
- 'hits': paginator.count,
- 'page_range': paginator.page_range,
- }
+
@@ -0,0 +1 @@
+<h1>About</h1>
Oops, something went wrong.

0 comments on commit 5424e16

Please sign in to comment.