simplifying the default template context_processors

370 views
Skip to first unread message

Collin Anderson

unread,
Jan 10, 2015, 5:40:02 PM1/10/15
to django-d...@googlegroups.com
Hi All,

In talking to Aymeric and other developers, we're starting to think about the usefulness of global template context_processors. It seems to us that ideally you should only need the "request" context processor. You could even imagine removing context_processors all together and having render() and class based views simply put the request in the context.

Some ways to avoid context processors:
{% static "my.css" %} instead of {{ STATIC_URL }} (a good idea regardless)
{{ mediafile.url }} instead of {{ MEDIA_URL }}
{{ request.user }} instead of {{ user }}
{% get_current_timezone as TIME_ZONE %}
{% get_current_language as LANGUAGE_CODE %}

I propose:

- Enabling the request context processor for new projects.
- Modifying the admin to work without context processors. https://code.djangoproject.com/ticket/24117
- Removing the other context processors for new projects. (Possibly waiting for 1.9).
- Possibly adding `request.messages` similar to `request.user`.
- Maybe adding `user.perms` or a template tag to replace {{ perms }}

This would be a somewhat controversial change. I think django originally tried hard to keep the request as separate from the response as possible. This would tie the two together even more. In my experience working with django projects, it's often very helpful to have the request object directly available in templates.

What do you think?

Collin


Marc Tamlyn

unread,
Jan 10, 2015, 6:19:15 PM1/10/15
to django-d...@googlegroups.com
I like it from a purity point of view, but I'm dreading updating through it and replacing every instance of `{{ STATIC_URL }}` in my templates...

I also have a number of small projects which add a custom context processor which add a certain queryset into the context every time because they form a part of the page navigational architecture. I don't really want to have to do this either 1) in every view or 2) via a custom template tag (because I hate custom template tags). A similar example would be the `add_page_if_missing`[1] context processor provided by feinCMS - it adds the best matching CMS page to every view's context so your custom views don't have to load the page themselves every time.

So I'm maybe +0 on the changes suggests, but I'm -0 on removing the whole concept of context processors, at least without a suitable "one hit" way of getting certain variables into the context of (nearly) every page.

Marc


--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/bf74b593-3fbb-46fe-89f6-ce280124d707%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Russell Keith-Magee

unread,
Jan 10, 2015, 6:42:21 PM1/10/15
to Django Developers
I feel like I've missed part of a discussion. We're talking about the contents of TEMPLATE_CONTEXT_PROCESSORS, right? What exactly is the issue with global context processors? 

Speaking personally - I'm definitely using global context processors at the moment, and it isn't clear to me what alternative you're proposing.

My use case - my site is multi-tenant, and on every request, I need to exact who the tenant is, and a couple of important attributes of the user in light of that tenancy. These attributes are all used in my site base template, so it's not like they are only used on some views - they really are used globally.

However, I think my use case ultimately isn't that much different to the messages case. contrib.messages is an optional app; if you're using it, then you're probably going to have a place in your base template where you want to display those messages. Making every view manually define that they want to have messages available sounds extremely onerous; it would be trivial to accidentally forget to add messages handling to a view, and site behavior would be dramatically impacted. 

At a conceptual level, I have no problem with the idea that there may be a collection of context variables that need to be applied to *every* view - or, at the very least, a significant subset of pages. I can see how you might couple reworked context processors and middleware into a reworked hierarchical URL structure (so a URL subtree has a particular set of context processors and middlewares; subtrees of that subtree inherit those augmentations; by default, there's only one URL subtree, so context processors and middlewares are global). 

So, unless there's a particularly compelling technical reason that I'm missing, or an equally "global" alternative being proposed, I'm -1 to removing TEMPLATE_CONTEXT_PROCESSORS.

Yours,
Russ Magee %-)

Collin Anderson

unread,
Jan 10, 2015, 10:33:44 PM1/10/15
to django-d...@googlegroups.com
Hi All,

Based on the early feedback, here's a scaled back proposal:

1. In the project_template settings.py for new projects:
- Enable the request context processor
- Keep the auth context processor
- Remove the rest (you can always install them by hand).
2. Make the admin work without needing specific context_processors enabled.

It sounds like context_processors as a feature are here to stay, but here are some alternatives anyway:
- Request attributes added by a middleware, like request.cart for a store. These can also be used in views.
- Assignment tags, like {% get_navigation as nav %}. I agree creating custom template tags is not fun.

Reusable apps can't assume specific context_processors are installed and may need to use alternatives anyway.

Collin

Josh Smeaton

unread,
Jan 10, 2015, 11:49:31 PM1/10/15
to django-d...@googlegroups.com
From my experience some reusable apps require (in their documentation) that specific context_processors are installed. I'm also -0 unless some decent alternative exists and there's a convincing argument why they aren't a good feature to have.

Cheers

Russell Keith-Magee

unread,
Jan 11, 2015, 12:20:18 AM1/11/15
to Django Developers
On Sun, Jan 11, 2015 at 11:33 AM, Collin Anderson <cmawe...@gmail.com> wrote:
Hi All,

Based on the early feedback, here's a scaled back proposal:

1. In the project_template settings.py for new projects:
- Enable the request context processor
- Keep the auth context processor
- Remove the rest (you can always install them by hand).

TEMPLATE_CONTEXT_PROCESSORS isn't in the project template at present; it is a default value inherited from global settings, whose initial value is:

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'django.template.context_processors.debug',
    'django.template.context_processors.i18n',
    'django.template.context_processors.media',
    'django.template.context_processors.static',
    # 'django.template.context_processors.request',
    'django.contrib.messages.context_processors.messages',
)

ISTM that we can't pare that down with just auth and request without having some pretty profound consequences on existing sites.

It also points out a second use case: the messages context processor shouldn't need to be manually installed; it should be automatically added as part of app configuration, if and only if messages is in INSTALLED_APPS. AppConfigs should make that sort of thing possible. If we're tinkering with context_processors, we might as well fix *all* the problems (although this is starting to looks like a 1.9-timeline project...)

2. Make the admin work without needing specific context_processors enabled.
 
This second point I definitely agree with. If anything, I think it's an argument for the "hierarchical URL config" thing; there isn't an inherent problem with context processors, it's that you need to have specific context processors in place in order for admin to work, and you shouldn't need to have 2+ pieces of configuration to get an app to work.
 
Russ %-)

Aymeric Augustin

unread,
Jan 11, 2015, 3:13:47 AM1/11/15
to django-d...@googlegroups.com
On 11 janv. 2015, at 06:20, Russell Keith-Magee <rus...@keith-magee.com> wrote:

> TEMPLATE_CONTEXT_PROCESSORS isn't in the project template at present; it is a default value inherited from global settings
> (…)
> ISTM that we can't pare that down with just auth and request without having some pretty profound consequences on existing sites.

In Django 1.8 — which isn’t the present yet, but soon will be — TEMPLATE_CONTEXT_PROCESSORS is deprecated and the project template contains:

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.tz',
'django.template.context_processors.media',
'django.template.context_processors.static',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

Collin is talking about that list. Since 1.8 hasn’t been released yet, there aren’t any backwards compatibility issues, not even with third-party documentation.

--
Aymeric.

Russell Keith-Magee

unread,
Jan 11, 2015, 3:43:52 AM1/11/15
to django-d...@googlegroups.com
Ah - got it. I checked the code, but didn't update my checkout from post-meta-refactor first. In that case, I can see that the backwards incompatibility I raised isn't an issue.

However, I'd still have some concerns about a project template that took out all the "useful" utilities, and required users to remember the exact spelling of half a dozen builtins to have functionality that would have historically been automatic.

Yours, 
Russ Magee %-)

Aymeric Augustin

unread,
Jan 11, 2015, 4:58:53 AM1/11/15
to django-d...@googlegroups.com
On 11 janv. 2015, at 09:43, Russell Keith-Magee <rus...@keith-magee.com> wrote:

> However, I'd still have some concerns about a project template that took out all the "useful" utilities, and required users to remember the exact spelling of half a dozen builtins to have functionality that would have historically been automatic.

I would argue that many of them are only useful in a very loose sense :-) and the most obviously useful one, request, is omitted.

I added the tz processor for consistency with the i18n processor but I never used it and I don’t think it’s needed.

I don’t remember using on the i18n processor either. Perhaps some i18n features implicitly depend on it. I would have to check.

The media and static processor enable obsolete template coding style. We shouldn’t encourage their use.

Without having spent much time to research the consequences — it's on my TODO list but Collin brought it up before I investigated — my straw man proposal is:

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

--
Aymeric.

Russell Keith-Magee

unread,
Jan 11, 2015, 7:20:57 PM1/11/15
to Django Developers
On Sun, Jan 11, 2015 at 5:58 PM, Aymeric Augustin <aymeric....@polytechnique.org> wrote:
On 11 janv. 2015, at 09:43, Russell Keith-Magee <rus...@keith-magee.com> wrote:

> However, I'd still have some concerns about a project template that took out all the "useful" utilities, and required users to remember the exact spelling of half a dozen builtins to have functionality that would have historically been automatic.

I would argue that many of them are only useful in a very loose sense :-) and the most obviously useful one, request, is omitted.

I added the tz processor for consistency with the i18n processor but I never used it and I don’t think it’s needed.

I don’t remember using on the i18n processor either. Perhaps some i18n features implicitly depend on it. I would have to check.

It doesn't look like it to me - I was under the impression that they did a bit more than just put TIME_ZONE, LANGUAGES, LANGUAGE_CODE and LANGUAGE_BIDI into context. 
 
The media and static processor enable obsolete template coding style. We shouldn’t encourage their use.

Without having spent much time to research the consequences — it's on my TODO list but Collin brought it up before I investigated — my straw man proposal is:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

Given that tz and i18n aren't doing anything significant, and media/static aren'tt doing it right, this list makes sense to me as defaults.

In my ideal world, we wouldn't need to specify these at all in the settings file - I'd almost propose that the Django template engine should have those context processors baked in by default, unless manually specified by the end user (i.e., if 'context_processors' in OPTIONS:). The goal of the simplification of the project template was to get all the extra cruft out of a default working template; having a bunch of boilerplate that many/most new users won't need to modify seems like a step backward in that regard.

Russ %-)

Carl Meyer

unread,
Jan 11, 2015, 9:28:58 PM1/11/15
to django-d...@googlegroups.com
Hi Russ,
On the other hand, there are some significant disadvantages to having
non-empty default values for list settings:

1) Less explicit - things show up in the template context and new users
have no idea where they might have come from.

2) As soon as you want to add a context processor, you have to find the
docs or `global_settings.py` and copy-paste the default value in, and if
you don't know that that's necessary it may not be obvious what you
broke or how to fix it.

I sympathize with the goal of a less-crufty default project template,
but in this case I find the argument for "explicit is better than
implicit" more compelling. It just makes sense that the default settings
for a template engine wouldn't magically add anything to the template
context.

Carl

signature.asc

Russell Keith-Magee

unread,
Jan 11, 2015, 11:25:44 PM1/11/15
to Django Developers
I agree with both these comments - hence my "almost propose" and "ideal world" qualifiers. I mentioned the idea purely to point out the conflict between the "simpler template" and "more explicit" goals of the project template (with the added irony that the core dev who simplified the template is also the one making it more complex :-)

Ultimately, I think you're right - explicit > implicit is a good argument. However, I would have made the same argument about some of the values that were taken out of the original project template. For more irony - the removal of TEMPLATE_CONTEXT_PROCESSORS was the one that bugged me most from the original template cleanup :-)

Russ %-)

cycleb...@gmail.com

unread,
Jan 12, 2015, 12:05:14 AM1/12/15
to django-d...@googlegroups.com
On 10/01/15 22:40, Collin Anderson wrote:
> Hi All,
>
> In talking to Aymeric and other developers, we're starting to think
> about the usefulness of global template context_processors. It seems to
> us that ideally you should only need the "request" context processor.
> You could even imagine removing context_processors all together and
> having render() and class based views simply put the request in the context.
>

FWIW, I habitually replace the multiple default context_processors with
a single custom processor which does the same thing. Then I add and
remove context items in a single place as the project goes on. The same
with third-party context_processors (they tend to be straightforward).

Backwards compatability aside, is a list of functions better than a
single function?


Russell Keith-Magee

unread,
Jan 12, 2015, 12:17:06 AM1/12/15
to Django Developers
From a performance point of view, a single function should have a *slight* advantage over multiple functions - there's only one name to resolve on startup, and individual function calls are moderately expensive operations in the Python VM. 

However, let's be clear - the advantage would be **SLIGHT** - verging on the point where it wouldn't be observable against background noise unless you have a *disturbingly* large number of context processors. It certainly wouldn't be my first port of call if I was looking to optimise a site. 

From an engineering point of view, you're gaining an almost imperceptible performance gain, in exchange for taking on the maintenance burden of code that is already being delivered and tested by others. Unless, of course, you're writing a single context function that calls the existing implementations - in which case you've just *decreased* site performance, because you're putting an additional function call on top of the existing overhead.

tl;dr - this isn't a performance issue; it's a clarity of expression issue.

Yours,
Russ Magee %-)

cycleb...@gmail.com

unread,
Jan 12, 2015, 12:51:05 AM1/12/15
to django-d...@googlegroups.com
On 12/01/15 05:16, Russell Keith-Magee wrote:
>
> On Mon, Jan 12, 2015 at 12:59 PM,
> <cycleb...@gmail.com
Performance isn't my concern at all, just "alternative-futuring". If you
guys are talking about altering how global context works, for me I like
the 'there is a single place in my code where I control what goes into
the context' idea. But I take your point about maintenance burden.


Aymeric Augustin

unread,
Jan 12, 2015, 1:48:48 AM1/12/15
to django-d...@googlegroups.com
Le 12 janv. 2015 à 05:25, Russell Keith-Magee <rus...@keith-magee.com> a écrit :

For more irony - the removal of TEMPLATE_CONTEXT_PROCESSORS was the one that bugged me most from the original template cleanup :-)

In hindsight it was a mistake.


-- 
Aymeric.

Collin Anderson

unread,
Jan 12, 2015, 11:34:17 AM1/12/15
to django-d...@googlegroups.com
Here's a PR for this change https://github.com/django/django/pull/3897
Reply all
Reply to author
Forward
0 new messages