Skip to content

Commit

Permalink
Allow mutable extra_context on TemplateViews
Browse files Browse the repository at this point in the history
Prior to this change, the `extra_context` attribute of a template view
was annotated as a `dict` (or `None`). This means that if a value is
provided, it *must* be a mutable object. Since this is an attribute on
the class, this creates mutable shared state, which is a source of bugs.
It was not possible to use an immutable mapping (`MappingProxyType or
the 3rd-party `frozendict`) without getting type-checking errors.

However, there is no need for this attribute to be mutable. This change
allows *any* mapping type, which allows authors to write template views
with immutable `extra_context` attributes.

Refs #1992
  • Loading branch information
samueljsb committed Mar 7, 2024
1 parent cfb6efc commit 5d22f38
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 2 deletions.
4 changes: 2 additions & 2 deletions django-stubs/views/generic/base.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
from collections.abc import Callable, Sequence
from typing import Any
from typing import Any, Mapping

from django.http.request import HttpRequest
from django.http.response import HttpResponse, HttpResponseBase
Expand All @@ -9,7 +9,7 @@ from django.utils.functional import _Getter
logger: logging.Logger

class ContextMixin:
extra_context: dict[str, Any] | None
extra_context: Mapping[str, Any] | None
def get_context_data(self, **kwargs: Any) -> dict[str, Any]: ...

class View:
Expand Down
16 changes: 16 additions & 0 deletions tests/typecheck/views/generic/test_template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
- case: generic_template_view_mutable_extra_context
main: |
from django.views.generic import TemplateView
class MyTemplateView(TemplateView):
template_name = "template.html"
extra_context = {}
- case: generic_template_view_immutable_extra_context
main: |
from types import MappingProxyType
from django.views.generic import TemplateView
class MyTemplateView(TemplateView):
template_name = "template.html"
extra_context = MappingProxyType({})

0 comments on commit 5d22f38

Please sign in to comment.