They could be added as a top-level cross-backend feature, but since in 1.8
they already exist as a DTL-specific feature in `OPTIONS`, they should be
added to the Jinja2 backend the same way.
Full IRC discussion transcript below. It's long, but seems useful to more
fully document the thinking here for posterity:
```
18:35 <+carljm> mYk: I'm upgrading a project to Django 1.8, and I am
wondering if we were wrong to not provide context processors for Jinja.
18:35 <+carljm> IIRC the rationale was something like "you don't need them
in Jinja because you can just put stuff into the env globals
directly", but this isn't really true - the point of
context processors is that they provide request-specific values, and
there's no obvious way to do that.
18:37 <+carljm> You can emulate by putting a function into the context
that returns some value, but then you have inefficiency if that function
does something non-trivial and its value is used in
multiple places.
18:37 <+carljm> For a concrete example, this project wants a serialized
(i.e. to primitive values), JSON-serializable representation of
request.user to be available in all templates.
18:38 <+carljm> In 1.7 this was done with a context processor that
provided that representation in a `me` variable.
18:39 <+carljm> In 1.8, without some context-processor equivalent, that
would have to become `me(request)` or `request|me` or something, and to
avoid serializing multiple times needlessly, it would
often turn into `{% set me = me(request) %}`
18:40 <+carljm> In looking into this, I also noticed that Flask does
provide context processors (just like Django's) atop Jinja2.
18:41 <+carljm> At the moment, I'm implementing context processors for the
Django Jinja2 backend. It's not hard, but unfortunately requires
copying most of the implementation of the Jinja2 backend
and its Template wrapper (they aren't really factored for subclass
customization)
18:41 <+carljm> I'd be very interested to hear if you think that I'm Doing
it Wrong and there's a better option available for this type of use
case.
18:43 <+carljm> Or if I'm not wrong, perhaps we should consider adding
support for OPTIONS['context_processors'] to the Jinja2 backend for 1.9.
18:46 <+carljm> Or at least make it easier to subclass the backend and add
that support. Specifically, this would mean factoring out an
"instantiate_template" (name to-be-bikeshedded) internal
method on the backend class, which would be called by both from_string
and get_template, and which would allow a subclass to
easily swap out both the Template wrapper class used and the arguments
passed to it.
18:50 <+carljm> (Actually with @jinja2.contextfunction you could remove
the explicit naming of the request in the above examples, but the other
issues still apply.)
18:51 <+jezdez> carljm: doesn’t django-jinja support ctx processors
natively?
18:52 <+jezdez> not that it answers your questions above, just something
that may buy you quicker results
18:54 <+carljm> jezdez: So does jingo (which is what we were using on 1.7)
18:55 <+carljm> Unfortunately jingo isn't 1.8-compatible (due to its use
of template internals that changed in 1.8); do you know if
django-jinja is?
18:55 <+carljm> In any case, part of the goal of this upgrade was to
switch from an external Jinja support package to the native support, so
I'll probably continue on this path. Already done with
adding context proc support, anyway :-)
18:55 <+jezdez> carljm: right, I think I’d like to move away from jingo in
general since it does a few things oddly
18:55 <+carljm> Thanks though!
18:56 <+jezdez> yeah, I heard django-jinja is 1.8 compatible
18:56 <+MarkusH> I'd probably look into what they are doing to provide
context processors and may adapt some of the monkey patches
18:56 <+carljm> jezdez: What are you thinking of specifically? I was
pretty happy with jingo as a pre-1.8 solution.
18:56 < pmachine> carljm: django-jinja provides it's own backend class for
1.8
18:56 <+carljm> Ah, nice!
18:56 <+jezdez> carljm: the helpers api is clunky and the monkey patches
just smell like tech debt
18:56 <+jezdez> I don’t see why we can’t have one and only one
implementation going forward now that 1.8 is out
18:57 <+jezdez> carljm: but yeah, I get what you’re saying, it’d be neat
to just move away from any library
18:57 <+jezdez> maybe in 2.0
18:57 <+jezdez> (not kidding)
18:57 <+carljm> Yeah; with 1.8 having a Jinja2 backend, I'd like to see
the "one and only implementation" be that one.
18:58 <+carljm> as in, if using the built-in backend is painful enough
that most people are using an external library on top of it still, we
should fix those pain points.
18:58 <+jezdez> so maybe we should spend more time on implementing
translation support and ctx processors?
18:58 <+carljm> yep :-)
[snip]
19:05 < pmachine> btw, I'm +1 on enabling context processors and making
the backend easier to subclass
19:07 <+carljm> pmachine: cool. I'll file an issue and PR for it, but I'd
like to see if mYk has any comments first.
19:08 <+carljm> (or more likely, two issues and two PRs)
19:14 <+mYk> am I being summoned?
19:14 <+mYk> I'm reading the backlog
19:15 <+mYk> carljm: part of the decision was: "it's easier not to provide
context processors at first and add them later than the opposite"
19:16 <+mYk> if Flask provides them, that's a strong argument
19:16 <+carljm> yes, definitely better to start minimal
19:16 <+carljm> Flask, and it seems every third-party Django-Jinja
adapter, too.
[snip discussion of Jinja backend subclassibility]
19:21 <+mYk> it seems more straightforward to me to just add support for
context processors
19:22 <+mYk> the question is -- should it be a "standard" option (like
DIRS and APP_DIRS) or a "backend-specific" option (which goes inside
OPTIONS)?
19:23 <+mYk> since 1.8 was released already and context_processors is a
"backend-specific" option of the Django backend, the latter option
seems less disruptive
19:23 <+carljm> yes, that was my feeling too
19:23 <+mYk> to be clear -- this is mostly a convenience & performance
thing, right?
19:24 <+mYk> you want to write {{ context_processor_output }} instead of
{{ context_processor(request) }} in templates
19:24 <+carljm> precisely, yes. it doesn't enable anything that is
impossible otherwise.
19:24 <+carljm> it's really the same thing you're doing with csrf_input
and csrf_token in the current backend
19:25 <+carljm> only there you've used yet another approach (Lazy), which
is one I'd dearly love to avoid :-)
19:25 <+mYk> well I had to in that case
19:25 <+mYk> coming back to context processors
19:25 <+mYk> I really like the explicitness of {{
context_processor(request) }}
19:26 <+carljm> yes, in that case it does have to be lazy so CSRF token
isn't triggered unnecessarily - but that approach does solve the same
cases
19:26 <+mYk> I think it fits well with Django's insistence on passing the
request to each view function
19:26 <+carljm> that in itself doesn't bother me much
19:26 <+carljm> but for a value which may be used many places, the
efficiency concern does.
19:27 <+mYk> it also clarifies whether you can render a given template
without a request (ie outside of the request-response cycle)
19:27 <+carljm> you can do {% set somevar = context_processor(request) %}
19:27 <+carljm> but for ubiqitous values (the only kind I would ever use a
context proc for anyway), that's ugly boilerplate to have in all
templates
19:28 <+mYk> do you often have computationally expensive things that you
use multiple times in a given template?
19:28 <+mYk> you could also cache the value in a private attribute of the
request, but that's ugly
19:28 <+carljm> yes, I considered that, too
19:29 <+mYk> if we step back for a minute, my general position is:
19:30 <+mYk> * real-life usage of context processors (starting with
django's built-in processors) leads me to think that they aren't a very
good API
19:30 <+carljm> in the current project, I have four context processors I
would use in Jinja. Only one of them (serialized user) is expensive
and widely-used enough that I'd be concerned about calling
it at every use site.
19:31 <+mYk> * they implicitly depend on the request, which is a net
negative for me, because I'm a strong proponent of dumb code
19:31 <+mYk> * if we come up with use cases for which they're clearly the
best answer, I'm happy to add them, but I'll still be afraid that
they will be misused
19:33 <+mYk> based on what you've described, I'm wondering if some sort of
caching isn't a better answer to your goal: optimizing performance
by avoiding repeated calls to an expensive function
19:34 <+carljm> ...thinking...
19:34 <+mYk> (and that will avoid paying the cost of calling that function
on pages that don't use it, if any)
19:35 <+mYk> one last idea: context processors look to me like response
middleware in disguise
19:35 <+mYk> if you have something complicated (or expensive) to do in
each response, perhaps doing it explicitly in a middleware would be a
good design
19:36 <+carljm> Yes, that's a variant of "cache the value in a private
attribute of the request", where the value instead becomes a public
attribute of the request, attached in a middleware.
19:37 <+carljm> I agree that solves the use case, and preserves the
explicit dependence on the request.
19:38 <+mYk> the various ideas I've suggested are merely shifting the
executing of this function and the caching of its results at various
points in the request/response cycle
19:38 <+carljm> It means the value is computed for all requests, even when
a template is not rendered.
19:38 <+mYk> I'm trying to optimize for "there should be one obvious way
to do it" and "explicit is better than implicit"
19:39 <+carljm> Yes. The question is whether "compute once when a template
is rendered, and make globally available in the template context"
has enough good use cases to provide API for.
19:39 <+mYk> it means the value is computed for all requests => maybe --
off the top of my head, I'm not sure how to tell if a given response
is going to render a template
19:39 <+carljm> My meta-concern is that it doesn't really matter whether
context processors are good API; Django is stuck with them. Unless we
deprecate them for DTL, the result of not providing them
for Jinja may be that people just use external Jinja backends instead
which provide them.
19:40 <+mYk> yes...
19:41 <+mYk> being technically correct serves us well if everyone keeps
using django-jinja...
19:41 <+mYk> that reminds me of mistakes I made in the time zone APIs,
which were technically correct at first, and are slowly becoming usable
by mortals
19:42 <+carljm> I think for my use case (which I think is the prototypical
best use case for a context processor), the best alternative would
be a cached_property on the request.
19:42 <+mYk> carljm: a realistic solution may be to provide context
processors for users who are used to them and don't want to think about
it,
and discussthe alternatives in the docs
19:42 <+carljm> Thus not computed unless accessed, but computed only once
when accessed.
19:42 <+carljm> Unfortunately Django makes that hard to do - trying to do
the equivalent in a middleware really requires use of Lazy
19:43 <+carljm> because you don't get to subclass Request, you just get to
monkeypatch it.
19:43 <+mYk> yup, AuthMiddleware has horrific code to set up request.user
19:44 <+carljm> yes, horrific code which has been rewritten at least once
because the previous version was both horrific and broken.
19:45 <+mYk> I'm not taking bets on whether the current version is also
horrific and broken :-)
19:45 <+carljm> Well, my conclusion at this point is that while I see the
arguments for explicit dependence on the request, I don't yet see a
practical alternative to a context processor that I would
be happy with for this use case.
19:45 <+mYk> okay
19:46 <+carljm> And given that, plus the precedent for context-processors
in Django and the likelihood that people will find an implementation
of them one way or another, I think I'd remain in favor of
adding them.
19:46 -!- f3lp <~f...@179.218.60.168> has joined #django-dev
19:46 <+carljm> (Perhaps with discussion of downsides and alternatives in
the docs.)
19:46 <+mYk> that works for me
19:47 <+mYk> keeping them as a "backend-specific" option will also de-
emphasize them a bit
19:47 <+mYk> (even though we're just doing this because the ship has
sailed with 1.8)
19:47 <+carljm> A cached function is the closest thing to an alternative
that I'd want to use, but then you have to decide between caching in a
private request attr (ick) vs some other caching approach
(which feels wrong because the value is logically request-scoped)
19:48 <+carljm> sure
19:48 <+carljm> And in practice unless we provide a seamless convenience
API for the request-scoped-cached-function approach, I don't think
anyone will choose to use it over context processors.
19:50 <+carljm> Ok, I will submit an issue (now) and PR (later).
19:51 <+carljm> Thanks for the thought-provoking discussion!
```
--
Ticket URL: <https://code.djangoproject.com/ticket/24694>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
Old description:
New description:
--
--
Ticket URL: <https://code.djangoproject.com/ticket/24694#comment:1>
* stage: Unreviewed => Accepted
--
Ticket URL: <https://code.djangoproject.com/ticket/24694#comment:2>
* cc: thebitguru (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/24694#comment:3>
Comment (by adamkerz):
I've just run into the same problem trying to use jinja2 and had a bit of
a look at middleware and the process_template_response method. From my
minor experimentation, it looks to me like that's at least roughly
equivalent to a context_processor - is there a reason that we can't get
rid of context_processors in favour of middleware? Seems like it will
support any template engine out of the box without having to modify the
template backend.
What are the differences between the two?
Also, doesn't django.utils.functional.lazy get around issues of loading it
whether it's used or not?
--
Ticket URL: <https://code.djangoproject.com/ticket/24694#comment:4>
Comment (by carljm):
Replying to [comment:4 adamkerz]:
> I've just run into the same problem trying to use jinja2 and had a bit
of a look at middleware and the process_template_response method. From my
minor experimentation, it looks to me like that's at least roughly
equivalent to a context_processor - is there a reason that we can't get
rid of context_processors in favour of middleware? Seems like it will
support any template engine out of the box without having to modify the
template backend.
>
> What are the differences between the two?
That's a very good point; I hadn't thought of that. I've used
`TemplateResponse` quite a bit with view _decorators_, but never really
with the middleware, so I hadn't thought of it as a "global" option.
That said, they aren't quite equivalent: `process_template_response` has
no effect unless you return a `TemplateResponse`. If you render a template
in any other way (say, render a template for creating an email or
something), or if you have a view from a third-party app that doesn't
return a `TemplateResponse`, your `process_template_response` will have no
effect. So I don't think we can consider `process_template_response` a
full replacement for context processors, but you're right that they can be
used similarly.
> Also, doesn't django.utils.functional.lazy get around issues of loading
it whether it's used or not?
Heh. Yeah, if you're willing to wrap everything in it :-) `lazy` is a
pretty nasty hack, and its abstraction leaks sometimes. If you're using
Jinja, I think a better solution than `lazy` is usually to just include a
function in the template context, and call it in the template.
--
Ticket URL: <https://code.djangoproject.com/ticket/24694#comment:5>
* Attachment "24694.py" added.
implementation as a subclass of existing backend
Comment (by carljm):
Since I never got around to making a PR for this for Django 1.9, I've
uploaded the implementation I've been using that subclasses the built-in
backend. This may be immediately useful to someone working in Django 1.8
or 1.9, and should also provide a reasonable basis for anyone motivated to
turn it into a proper patch. It needs to be integrated into the main
Jinja2 backend instead of being a subclass, and needs tests and docs
added.
--
Ticket URL: <https://code.djangoproject.com/ticket/24694#comment:6>
* cc: berker.peksag@… (added)
* owner: nobody => berkerpeksag
* has_patch: 0 => 1
* status: new => assigned
Comment:
https://github.com/django/django/pull/6840
--
Ticket URL: <https://code.djangoproject.com/ticket/24694#comment:7>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"52a991d9766de08b411ee05e2166ed9576da3458" 52a991d9]:
{{{
#!CommitTicketReference repository=""
revision="52a991d9766de08b411ee05e2166ed9576da3458"
Fixed #24694 -- Added support for context_processors to Jinja2 backend.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/24694#comment:8>
Comment (by aaugustin):
Unfortunately, the discussion of the drawbacks of this API didn't make it
into the documentation, so we're ending up with exactly what PEP 182 was
designed to avoid :-(
--
Ticket URL: <https://code.djangoproject.com/ticket/24694#comment:9>
Comment (by timgraham):
Sorry, I didn't read that entire discussion. I created #26817 for that
documentation.
--
Ticket URL: <https://code.djangoproject.com/ticket/24694#comment:10>
Old description:
New description:
Conclusion from IRC discussion: There are advantages to being explicit
about request-dependence in the template (which context processors are
not), but there's currently no convenient alternative to context
processors for computing a non-trivial request-dependent value that you
want computed only once per template render (and not at all if no template
is rendered). And even if we don't like context processors as an API, they
have strong precedent in Django, so people will probably find a way to use
them regardless (e.g. using django-jinja instead of the built-in Jinja2
backend).
They could be added as a top-level cross-backend feature, but since in 1.8
they already exist as a DTL-specific feature in `OPTIONS`, they should be
added to the Jinja2 backend the same way.
Full IRC discussion transcript below. It's long, but seems useful to more
fully document the thinking here for posterity:
{{{
<carljm> mYk: I am wondering if we were wrong to not provide context
processors for Jinja. IIRC the rationale was something like "you don't
need them in Jinja because you can just put stuff into the env globals
directly", but this isn't really true - the point of context processors is
that they provide request-specific values, and there's no obvious way to
do that.
You can emulate by putting a function into the context that returns some
value, but then you have inefficiency if that function does something non-
trivial and its value is used in multiple places.
For a concrete example, this project wants a serialized (i.e. to primitive
values), JSON-serializable representation of request.user to be available
in all templates.
In 1.7 this was done with a context processor that provided that
representation in a `me` variable. In 1.8, without some context-processor
equivalent, that would have to become `me(request)` or `request|me` or
something, and to avoid serializing multiple times needlessly, it would
often turn into `{% set me = me(request) %}`
In looking into this, I also noticed that Flask does provide context
processors (just like Django's) atop Jinja2.
At the moment, I'm implementing context processors for the Django Jinja2
backend. It's not hard, but unfortunately requires copying most of the
implementation of the Jinja2 backend and its Template wrapper (they aren't
really factored for subclass customization).
I'd be very interested to hear if you think that I'm Doing it Wrong and
there's a better option available for this type of use case. Or if I'm not
wrong, perhaps we should consider adding support for
OPTIONS['context_processors'] to the Jinja2 backend for 1.9. Or at least
make it easier to subclass the backend and add that support. Specifically,
this would mean factoring out an "instantiate_template" (name to-be-
bikeshedded) internal method on the backend class, which would be called
by both from_string and get_template, and which would allow a subclass to
easily swap out both the Template wrapper class used and the arguments
passed to it. (Actually with @jinja2.contextfunction you could remove the
explicit naming of the request in the above examples, but the other issues
still apply.)
<jezdez> doesn’t django-jinja support ctx processors natively? not that it
answers your questions above, just something that may buy you quicker
results.
<carljm> So does jingo (which is what we were using on 1.7). Unfortunately
jingo isn't 1.8-compatible (due to its use of template internals that
changed in 1.8); do you know if django-jinja is? In any case, part of the
goal of this upgrade was to switch from an external Jinja support package
to the native support, so I'll probably continue on this path. Already
done with adding context proc support, anyway :-)
<jezdez> right, I think I’d like to move away from jingo in general since
it does a few things oddly
<carljm> Thanks though!
<jezdez> yeah, I heard django-jinja is 1.8 compatible
<carljm> What are you thinking of specifically? I was pretty happy with
jingo as a pre-1.8 solution.
<pmachine> django-jinja provides it's own backend class for 1.8
<carljm> Ah, nice!
<jezdez> The helpers api is clunky and the monkey patches just smell like
tech debt. I don’t see why we can’t have one and only one implementation
going forward now that 1.8 is out, but yeah, I get what you’re saying,
it’d be neat to just move away from any library.
<carljm> Yeah; with 1.8 having a Jinja2 backend, I'd like to see the "one
and only implementation" be that one. As in, if using the built-in backend
is painful enough that most people are using an external library on top of
it still, we should fix those pain points.
<jezdez> so maybe we should spend more time on implementing translation
support and ctx processors?
<carljm> yep :-)
<pmachine> btw, I'm +1 on enabling context processors and making the
backend easier to subclass
<carljm> I'll file an issue and PR for it, but I'd like to see if mYk has
any comments first.
<mYk> carljm: part of the decision was: "it's easier not to provide
context processors at first and add them later than the opposite". If
Flask provides them, that's a strong argument.
<carljm> yes, definitely better to start minimal
<carljm> Flask, and it seems every third-party Django-Jinja adapter, too.
<mYk> it seems more straightforward to me to just add support for context
processors. The question is -- should it be a "standard" option (like DIRS
and APP_DIRS) or a "backend-specific" option (which goes inside OPTIONS)?
Since 1.8 was released already and context_processors is a "backend-
specific" option of the Django backend, the latter option seems less
disruptive
<carljm> yes, that was my feeling too
<mYk> to be clear -- this is mostly a convenience & performance thing,
right? you want to write {{ context_processor_output }} instead of {{
context_processor(request) }} in templates
<carljm> precisely, yes. it doesn't enable anything that is impossible
otherwise. It's really the same thing you're doing with csrf_input and
csrf_token in the current backend, only there you've used yet another
approach (Lazy), which is one I'd dearly love to avoid :-)
<mYk> well I had to in that case. coming back to context processors, I
really like the explicitness of {{ context_processor(request) }}
<carljm> yes, in that case it does have to be lazy so CSRF token isn't
triggered unnecessarily - but that approach does solve the same cases
<mYk> I think it fits well with Django's insistence on passing the request
to each view function
<carljm> that in itself doesn't bother me much, but for a value which may
be used many places, the efficiency concern does.
<mYk> it also clarifies whether you can render a given template without a
request (ie outside of the request-response cycle)
<carljm> you can do {% set somevar = context_processor(request) %}, but
for ubiquitous values (the only kind I would ever use a context proc for
anyway), that's ugly boilerplate to have in all templates
<mYk> do you often have computationally expensive things that you use
multiple times in a given template?. You could also cache the value in a
private attribute of the request, but that's ugly
<carljm> yes, I considered that, too. In the current project, I have four
context processors I would use in Jinja. Only one of them (serialized
user) is expensive and widely-used enough that I'd be concerned about
calling it at every use site.
<mYk> if we step back for a minute, my general position is:
* real-life usage of context processors (starting with django's built-in
processors) leads me to think that they aren't a very good API
* they implicitly depend on the request, which is a net negative for me,
because I'm a strong proponent of dumb code
* if we come up with use cases for which they're clearly the best answer,
I'm happy to add them, but I'll still be afraid that they will be misused
based on what you've described, I'm wondering if some sort of caching
isn't a better answer to your goal: optimizing performance by avoiding
repeated calls to an expensive function
<carljm> ...thinking...
<mYk> (and that will avoid paying the cost of calling that function on
pages that don't use it, if any)
one last idea: context processors look to me like response middleware in
disguise. If you have something complicated (or expensive) to do in each
response, perhaps doing it explicitly in a middleware would be a good
design.
<carljm> Yes, that's a variant of "cache the value in a private attribute
of the request", where the value instead becomes a public attribute of the
request, attached in a middleware. I agree that solves the use case, and
preserves the explicit dependence on the request.
<mYk> the various ideas I've suggested are merely shifting the executing
of this function and the caching of its results at various points in the
request/response cycle
<carljm> It means the value is computed for all requests, even when a
template is not rendered.
<mYk> I'm trying to optimize for "there should be one obvious way to do
it" and "explicit is better than implicit"
<carljm> Yes. The question is whether "compute once when a template is
rendered, and make globally available in the template context" has enough
good use cases to provide API for.
<mYk> it means the value is computed for all requests => maybe -- off the
top of my head, I'm not sure how to tell if a given response is going to
render a template
<carljm> My meta-concern is that it doesn't really matter whether context
processors are good API; Django is stuck with them. Unless we deprecate
them for DTL, the result of not providing them for Jinja may be that
people just use external Jinja backends instead which provide them.
<mYk> yes... being technically correct serves us well if everyone keeps
using django-jinja... that reminds me of mistakes I made in the time zone
APIs, which were technically correct at first, and are slowly becoming
usable by mortals
<carljm> I think for my use case (which I think is the prototypical best
use case for a context processor), the best alternative would be a
cached_property on the request.
<mYk> carljm: a realistic solution may be to provide context processors
for users who are used to them and don't want to think about it, and
discuss the alternatives in the docs
<carljm> Thus not computed unless accessed, but computed only once when
accessed. Unfortunately Django makes that hard to do - trying to do the
equivalent in a middleware really requires use of Lazy because you don't
get to subclass Request, you just get to monkeypatch it.
<mYk> yup, AuthMiddleware has horrific code to set up request.user
<carljm> yes, horrific code which has been rewritten at least once because
the previous version was both horrific and broken.
<mYk> I'm not taking bets on whether the current version is also horrific
and broken :-)
<carljm> Well, my conclusion at this point is that while I see the
arguments for explicit dependence on the request, I don't yet see a
practical alternative to a context processor that I would be happy with
for this use case.
<mYk> okay
<carljm> And given that, plus the precedent for context-processors in
Django and the likelihood that people will find an implementation of them
one way or another, I think I'd remain in favor of adding them. (Perhaps
with discussion of downsides and alternatives in the docs.)
<mYk> that works for me. keeping them as a "backend-specific" option will
also de-emphasize them a bit (even though we're just doing this because
the ship has sailed with 1.8)
<carljm> A cached function is the closest thing to an alternative that I'd
want to use, but then you have to decide between caching in a private
request attr (ick) vs some other caching approach (which feels wrong
because the value is logically request-scoped)
<carljm> sure, and in practice unless we provide a seamless convenience
API for the request-scoped-cached-function approach, I don't think anyone
will choose to use it over context processors.
}}}
--
Comment (by Tim Graham):
(edited IRC conversation for readability)
--
Ticket URL: <https://code.djangoproject.com/ticket/24694#comment:11>