Kaydet (Commit) 8663bc11 authored tarafından Claude Paroz's avatar Claude Paroz

Fixed #16074 -- Added ContextMixin to class-based generic views to handle…

Fixed #16074 -- Added ContextMixin to class-based generic views to handle get_context_data. Thanks emyller, Luke Plant, Preston Holmes for working on the ticket and patch.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@17875 bcc190cf-cafb-0310-a4f2-bffc1f526a37
üst b4a98271
......@@ -8,6 +8,16 @@ from django.utils.decorators import classonlymethod
logger = getLogger('django.request')
class ContextMixin(object):
"""
A default context mixin that passes the keyword arguments received by
get_context_data as the template context.
"""
def get_context_data(self, **kwargs):
return kwargs
class View(object):
"""
Intentionally simple parent class for all views. Only implements
......@@ -110,17 +120,13 @@ class TemplateResponseMixin(object):
return [self.template_name]
class TemplateView(TemplateResponseMixin, View):
class TemplateView(TemplateResponseMixin, ContextMixin, View):
"""
A view that renders a template.
A view that renders a template. This view is different from all the others
insofar as it also passes ``kwargs`` as ``params`` to the template context.
"""
def get_context_data(self, **kwargs):
return {
'params': kwargs
}
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
context = self.get_context_data(params=kwargs)
return self.render_to_response(context)
......
......@@ -217,16 +217,6 @@ class BaseDateListView(MultipleObjectMixin, DateMixin, View):
return date_list
def get_context_data(self, **kwargs):
"""
Get the context. Must return a Context (or subclass) instance.
"""
items = kwargs.pop('object_list')
context = super(BaseDateListView, self).get_context_data(object_list=items)
context.update(kwargs)
return context
class BaseArchiveIndexView(BaseDateListView):
"""
Base class for archives of date-based items.
......
......@@ -2,10 +2,10 @@ from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
from django.http import Http404
from django.utils.encoding import smart_str
from django.utils.translation import ugettext as _
from django.views.generic.base import TemplateResponseMixin, View
from django.views.generic.base import TemplateResponseMixin, ContextMixin, View
class SingleObjectMixin(object):
class SingleObjectMixin(ContextMixin):
"""
Provides the ability to retrieve a single object for further manipulation.
"""
......@@ -86,11 +86,12 @@ class SingleObjectMixin(object):
return None
def get_context_data(self, **kwargs):
context = kwargs
context = {}
context_object_name = self.get_context_object_name(self.object)
if context_object_name:
context[context_object_name] = self.object
return context
context.update(kwargs)
return super(SingleObjectMixin, self).get_context_data(**context)
class BaseDetailView(SingleObjectMixin, View):
......
from django.forms import models as model_forms
from django.core.exceptions import ImproperlyConfigured
from django.http import HttpResponseRedirect
from django.views.generic.base import TemplateResponseMixin, View
from django.views.generic.base import TemplateResponseMixin, ContextMixin, View
from django.views.generic.detail import (SingleObjectMixin,
SingleObjectTemplateResponseMixin, BaseDetailView)
class FormMixin(object):
class FormMixin(ContextMixin):
"""
A mixin that provides a way to show and handle a form in a request.
"""
......@@ -45,9 +45,6 @@ class FormMixin(object):
})
return kwargs
def get_context_data(self, **kwargs):
return kwargs
def get_success_url(self):
if self.success_url:
url = self.success_url
......@@ -113,13 +110,14 @@ class ModelFormMixin(FormMixin, SingleObjectMixin):
return super(ModelFormMixin, self).form_valid(form)
def get_context_data(self, **kwargs):
context = kwargs
context = {}
if self.object:
context['object'] = self.object
context_object_name = self.get_context_object_name(self.object)
if context_object_name:
context[context_object_name] = self.object
return context
context.update(kwargs)
return super(ModelFormMixin, self).get_context_data(**context)
class ProcessFormView(View):
......
......@@ -3,10 +3,10 @@ from django.core.exceptions import ImproperlyConfigured
from django.http import Http404
from django.utils.encoding import smart_str
from django.utils.translation import ugettext as _
from django.views.generic.base import TemplateResponseMixin, View
from django.views.generic.base import TemplateResponseMixin, ContextMixin, View
class MultipleObjectMixin(object):
class MultipleObjectMixin(ContextMixin):
allow_empty = True
queryset = None
model = None
......@@ -103,10 +103,10 @@ class MultipleObjectMixin(object):
'is_paginated': False,
'object_list': queryset
}
context.update(kwargs)
if context_object_name is not None:
context[context_object_name] = queryset
return context
context.update(kwargs)
return super(MultipleObjectMixin, self).get_context_data(**context)
class BaseListView(MultipleObjectMixin, View):
......
......@@ -270,6 +270,16 @@ more::
context['book_list'] = Book.objects.all()
return context
.. note::
Generally, get_context_data will merge the context data of all parent classes
with those of the current class. To preserve this behavior in your own classes
where you want to alter the context, you should be sure to call
get_context_data on the super class. When no two classes try to define the same
key, this will give the expected results. However if any class attempts to
override a key after parent classes have set it (after the call to super), any
children of that class will also need to explictly set it after super if they
want to be sure to override all parents.
Viewing subsets of objects
--------------------------
......
from __future__ import absolute_import
import time
from django.core.exceptions import ImproperlyConfigured
......@@ -6,6 +8,7 @@ from django.test import TestCase, RequestFactory
from django.utils import unittest
from django.views.generic import View, TemplateView, RedirectView
from . import views
class SimpleView(View):
"""
......@@ -331,3 +334,19 @@ class RedirectViewTest(unittest.TestCase):
# we can't use self.rf.get because it always sets QUERY_STRING
response = RedirectView.as_view(url='/bar/')(self.rf.request(PATH_INFO='/foo/'))
self.assertEqual(response.status_code, 301)
class GetContextDataTest(unittest.TestCase):
def test_get_context_data_super(self):
test_view = views.CustomContextView()
context = test_view.get_context_data(kwarg_test='kwarg_value')
# the test_name key is inserted by the test classes parent
self.assertTrue('test_name' in context)
self.assertEqual(context['kwarg_test'], 'kwarg_value')
self.assertEqual(context['custom_key'], 'custom_value')
# test that kwarg overrides values assigned higher up
context = test_view.get_context_data(test_name='test_value')
self.assertEqual(context['test_name'], 'test_value')
from __future__ import absolute_import
from .base import ViewTest, TemplateViewTest, RedirectViewTest
from .base import (ViewTest, TemplateViewTest, RedirectViewTest,
GetContextDataTest)
from .dates import (ArchiveIndexViewTests, YearArchiveViewTests,
MonthArchiveViewTests, WeekArchiveViewTests, DayArchiveViewTests,
DateDetailViewTests)
......
......@@ -14,10 +14,9 @@ class CustomTemplateView(generic.TemplateView):
template_name = 'generic_views/about.html'
def get_context_data(self, **kwargs):
return {
'params': kwargs,
'key': 'value'
}
context = super(CustomTemplateView, self).get_context_data(**kwargs)
context.update({'key': 'value'})
return context
class ObjectDetail(generic.DetailView):
......@@ -184,3 +183,18 @@ class BookDetailGetObjectCustomQueryset(BookDetail):
def get_object(self, queryset=None):
return super(BookDetailGetObjectCustomQueryset,self).get_object(
queryset=Book.objects.filter(pk=2))
class CustomContextView(generic.detail.SingleObjectMixin, generic.View):
model = Book
object = Book(name='dummy')
def get_object(self):
return Book(name="dummy")
def get_context_data(self, **kwargs):
context = {'custom_key': 'custom_value'}
context.update(kwargs)
return super(CustomContextView, self).get_context_data(**context)
def get_context_object_name(self, obj):
return "test_name"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment