This week’s email is out with a delay thanks to a scheduling snafu, apologies to those left waiting on Tuesday morning.
Two issues prior we discussed _email _in Django apps and in doing so I brought up another topic: templates. One step that can help manage email in any Django project is developing a consistent system for naming email templates and using email base templates.
So what about “regular” templates? Like email, HTML templates are one of the “batteries included” in Django, and while templates _do _get quite a bit of attention, it’s mostly in how to build cool things with them - a good thing, surely - and not so much how to make them manageable.
Confusing template organization and naming is the most obvious template problems in Django projects. The first step is to pick a strategy and to _be consistent _with it, whether that’s a naming strategy or location strategy.
That said, for most projects we’ve found that grouping all project templates into a root ‘templates’ folder organized by app name is the best strategy for managing project templates. The alternative, locating them within app folders in template sub folders certainly works, however that’s geared more toward reusable apps. The benefit of using the project templates folder is that in addition to working on individual templates, developers tend to work on multiple templates at a time in such a way that it’s clearer seeing all of the templates together. This is especially true for teams large enough to have some division of specialization (e.g. front end specialists).
To get a bit more granular, any given template folder (e.g. root or app) may and should have subfolders specific to features of the template rendering system, e.g. “includes”, “emails”, “tags”, etc. Any template used in more than one app should be moved up the project namespace.
As to template names, the convention propagated by Django’s generic views, including model and purpose (or action) is very good to follow. It doesn’t always fit, but when it does it makes clear what a template does and why.
Why bother with so much effort around names of files and their folder locations? Because ultimately these things save developer time, otherwise lost in either figuring things out or solving unnecessary errors.
There are a lot of ways of getting both data (context) and conditional content into Django templates. The view provides a context, and you can use context processors to add globally available data, you can grab data from the request added by middleware, you can include templates, extend from templates, call template tags from within templates…
But some things work better than others.
The first thing to understand is whether you’re concerned primarily about transforming some data or some kind of dynamic rendering.
For data, if it will be accessed across multiple views, especially across apps, then a context processor may be a good idea. The downside to context processors is that you’re adding to the “global template namespace” but they tend to simplify view contexts to the view specific data. Context processors can simplify views that require extensive context management from super classes, as well.
_Include _statements work best when the template to include is (a) non trivial markup and (b) used in multiple locations. For instance a navigation menu with only minor data changes could be implemented nicely with an include. Includes can also be used to break out markup that may not be used in many other files but by virtue of being separated makes the original much easier to read.
Template tags can be used to satisfy both, either creating a product from one or more values in the context or being used to render some non-trivial template logic. The downside to template tags is that they add at least a step in understanding the structure of templates. They should be used when the alternative include file would instead by riddled with if/then statements. Hint: that’s one of their single most important roles, solving for nasty template logic which is hard to read, update, and debug. Tags also have the feature of being testable on their own in a way that includes do not.
By far the biggest problem maintaining templates in Django projects is overly complex template logic. Judicious use of context variables and template tags goes a long way toward solving this, not to mention precalculating values in the view itself. If you take nothing else away from this email, I hope its this.
First, a little “trick” that a lot of developers seem to miss: the template names in Django templates are string literals and can be replaced with template variables. Yep, you can specify the template from which yours inherits from the view. Why would you need to do this? Well, you can use this for conditionally showing a different base template where, for example, you might implement a UI upgrade. There’s also a strategy I learned a while back from a colleague whereby you can use this to conditionally extend from a ‘blank’ template thus cleanly reusing a “normal” template for both full and partial (AJAX) requests.
The other reason this is interesting is that it makes it easier to update the global UI by simply changing the base name that templates inherit from. This can’t always be done, of course, but it allows you to dynamically switch between a legacy base template and an updated base template, keeping them available at the flick of a switch. This makes the final step in updating a project’s templates that much simpler.
P.s. sometimes I have to radically shorten an email from what its subject demanded, and this is one of those cases. If there’s an aspect of wrangling Django templates you’d like to hear more about, just reply and let me know.
Learn from more articles like this how to make the most out of your existing Django site.