diff --git a/django/views/generic/base.py b/django/views/generic/base.py index d9be6e17e8..7938aeaebc 100644 --- a/django/views/generic/base.py +++ b/django/views/generic/base.py @@ -18,10 +18,13 @@ class ContextMixin: A default context mixin that passes the keyword arguments received by get_context_data() as the template context. """ + extra_context = None def get_context_data(self, **kwargs): if 'view' not in kwargs: kwargs['view'] = self + if self.extra_context is not None: + kwargs.update(self.extra_context) return kwargs diff --git a/docs/ref/class-based-views/base.txt b/docs/ref/class-based-views/base.txt index 2928880ec6..6230f1181e 100644 --- a/docs/ref/class-based-views/base.txt +++ b/docs/ref/class-based-views/base.txt @@ -156,6 +156,9 @@ MRO is an acronym for Method Resolution Order. * Populated (through :class:`~django.views.generic.base.ContextMixin`) with the keyword arguments captured from the URL pattern that served the view. + * You can also add context using the + :attr:`~django.views.generic.base.ContextMixin.extra_context` keyword + argument for :meth:`~django.views.generic.base.View.as_view`. ``RedirectView`` ================ diff --git a/docs/ref/class-based-views/flattened-index.txt b/docs/ref/class-based-views/flattened-index.txt index 25ac146500..148e95a6af 100644 --- a/docs/ref/class-based-views/flattened-index.txt +++ b/docs/ref/class-based-views/flattened-index.txt @@ -40,6 +40,7 @@ Simple generic views **Attributes** (with optional accessor): * :attr:`~django.views.generic.base.TemplateResponseMixin.content_type` +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` [:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`] * :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine` @@ -92,6 +93,7 @@ Detail Views * :attr:`~django.views.generic.base.TemplateResponseMixin.content_type` * :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`] +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.detail.SingleObjectMixin.model` * :attr:`~django.views.generic.detail.SingleObjectMixin.pk_url_kwarg` @@ -128,6 +130,7 @@ List Views * :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`] * :attr:`~django.views.generic.base.TemplateResponseMixin.content_type` * :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`] +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.list.MultipleObjectMixin.model` * :attr:`~django.views.generic.list.MultipleObjectMixin.ordering` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_ordering`] @@ -163,6 +166,7 @@ Editing views **Attributes** (with optional accessor): * :attr:`~django.views.generic.base.TemplateResponseMixin.content_type` +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.edit.FormMixin.form_class` [:meth:`~django.views.generic.edit.FormMixin.get_form_class`] * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.edit.FormMixin.initial` [:meth:`~django.views.generic.edit.FormMixin.get_initial`] @@ -195,6 +199,7 @@ Editing views * :attr:`~django.views.generic.base.TemplateResponseMixin.content_type` * :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`] +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.edit.ModelFormMixin.fields` * :attr:`~django.views.generic.edit.FormMixin.form_class` [:meth:`~django.views.generic.edit.ModelFormMixin.get_form_class`] * :attr:`~django.views.generic.base.View.http_method_names` @@ -238,6 +243,7 @@ Editing views * :attr:`~django.views.generic.base.TemplateResponseMixin.content_type` * :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`] +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.edit.ModelFormMixin.fields` * :attr:`~django.views.generic.edit.FormMixin.form_class` [:meth:`~django.views.generic.edit.ModelFormMixin.get_form_class`] * :attr:`~django.views.generic.base.View.http_method_names` @@ -281,6 +287,7 @@ Editing views * :attr:`~django.views.generic.base.TemplateResponseMixin.content_type` * :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`] +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.detail.SingleObjectMixin.model` * :attr:`~django.views.generic.detail.SingleObjectMixin.pk_url_kwarg` @@ -322,6 +329,7 @@ Date-based views * :attr:`~django.views.generic.base.TemplateResponseMixin.content_type` * :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`] * :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`] +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.list.MultipleObjectMixin.model` * :attr:`~django.views.generic.list.MultipleObjectMixin.ordering` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_ordering`] @@ -361,6 +369,7 @@ Date-based views * :attr:`~django.views.generic.base.TemplateResponseMixin.content_type` * :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`] * :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`] +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.dates.YearArchiveView.make_object_list` [:meth:`~django.views.generic.dates.YearArchiveView.get_make_object_list`] * :attr:`~django.views.generic.list.MultipleObjectMixin.model` @@ -403,6 +412,7 @@ Date-based views * :attr:`~django.views.generic.base.TemplateResponseMixin.content_type` * :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`] * :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`] +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.list.MultipleObjectMixin.model` * :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`] @@ -448,6 +458,7 @@ Date-based views * :attr:`~django.views.generic.base.TemplateResponseMixin.content_type` * :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`] * :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`] +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.list.MultipleObjectMixin.model` * :attr:`~django.views.generic.list.MultipleObjectMixin.ordering` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_ordering`] @@ -493,6 +504,7 @@ Date-based views * :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`] * :attr:`~django.views.generic.dates.DayMixin.day` [:meth:`~django.views.generic.dates.DayMixin.get_day`] * :attr:`~django.views.generic.dates.DayMixin.day_format` [:meth:`~django.views.generic.dates.DayMixin.get_day_format`] +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.list.MultipleObjectMixin.model` * :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`] @@ -542,6 +554,7 @@ Date-based views * :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`] * :attr:`~django.views.generic.dates.DayMixin.day` [:meth:`~django.views.generic.dates.DayMixin.get_day`] * :attr:`~django.views.generic.dates.DayMixin.day_format` [:meth:`~django.views.generic.dates.DayMixin.get_day_format`] +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.list.MultipleObjectMixin.model` * :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`] @@ -590,6 +603,7 @@ Date-based views * :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`] * :attr:`~django.views.generic.dates.DayMixin.day` [:meth:`~django.views.generic.dates.DayMixin.get_day`] * :attr:`~django.views.generic.dates.DayMixin.day_format` [:meth:`~django.views.generic.dates.DayMixin.get_day_format`] +* :attr:`~django.views.generic.base.ContextMixin.extra_context` * :attr:`~django.views.generic.base.View.http_method_names` * :attr:`~django.views.generic.detail.SingleObjectMixin.model` * :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`] diff --git a/docs/ref/class-based-views/mixins-simple.txt b/docs/ref/class-based-views/mixins-simple.txt index a2601a1b08..012d509716 100644 --- a/docs/ref/class-based-views/mixins-simple.txt +++ b/docs/ref/class-based-views/mixins-simple.txt @@ -7,6 +7,19 @@ Simple mixins .. class:: django.views.generic.base.ContextMixin + **Attributes** + + .. attribute:: extra_context + + .. versionadded:: 2.0 + + A dictionary to include in the context. This is a convenient way of + specifying some simple context in + :meth:`~django.views.generic.base.View.as_view`. Example usage:: + + from django.views.generic import TemplateView + TemplateView.as_view(extra_context={'title': 'Custom Title'}) + **Methods** .. method:: get_context_data(**kwargs) diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt index 3985f158fd..e58c2588cc 100644 --- a/docs/releases/2.0.txt +++ b/docs/releases/2.0.txt @@ -189,7 +189,8 @@ Forms Generic Views ~~~~~~~~~~~~~ -* ... +* The new :attr:`.ContextMixin.extra_context` attribute allows adding context + in ``View.as_view()``. Internationalization ~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/topics/class-based-views/mixins.txt b/docs/topics/class-based-views/mixins.txt index d0f0bddbc2..8da0834866 100644 --- a/docs/topics/class-based-views/mixins.txt +++ b/docs/topics/class-based-views/mixins.txt @@ -62,7 +62,8 @@ interface to working with templates in class-based views. any data they want to ensure is in there as keyword arguments. ``get_context_data()`` returns a dictionary; in ``ContextMixin`` it simply returns its keyword arguments, but it is common to override this to - add more members to the dictionary. + add more members to the dictionary. You can also use the + :attr:`~django.views.generic.base.ContextMixin.extra_context` attribute. Building up Django's generic class-based views ============================================== diff --git a/tests/generic_views/test_base.py b/tests/generic_views/test_base.py index 9f9cde9aef..8215e67e1a 100644 --- a/tests/generic_views/test_base.py +++ b/tests/generic_views/test_base.py @@ -343,6 +343,10 @@ class TemplateViewTest(SimpleTestCase): match = resolve('/template/login_required/') self.assertIs(match.func.view_class, TemplateView) + def test_extra_context(self): + response = self.client.get('/template/extra_context/') + self.assertEqual(response.context['title'], 'Title') + @override_settings(ROOT_URLCONF='generic_views.urls') class RedirectViewTest(SimpleTestCase): diff --git a/tests/generic_views/urls.py b/tests/generic_views/urls.py index 3475bfc357..209ce2285f 100644 --- a/tests/generic_views/urls.py +++ b/tests/generic_views/urls.py @@ -22,6 +22,8 @@ urlpatterns = [ url(r'^template/cached/(?P\w+)/$', cache_page(2.0)(TemplateView.as_view(template_name='generic_views/about.html'))), + url(r'^template/extra_context/$', + TemplateView.as_view(template_name='generic_views/about.html', extra_context={'title': 'Title'})), # DetailView url(r'^detail/obj/$',