11. Output formatting

Robert Crowther Mar 2022

PrevNext

Until now, we have mainly done some basic templating of Genric View information. Sometimes you may want to do more with the output data, especially how it is rendered. For example, perhaps you would like a time to be rendered on an image of a clock? Or delve some further information from the information provided, such as a wordcount on text content? A kind of internationalization can be done using tags, on the basis that depending on the user, a Spanish text has been requested, not Danish…

Builtin template tags

The Django templating system has a system called ‘template tags’. This system is powerful— each tag is, underneath, a call to a method/proceedure. Which means the template tags can take parameters. If you push it, the system gets distracted, because template tags are an imitation of Python syntax, not the real thing. But, it’s still an impressive system and, importantly, it let’s you get things done quickly.

My favourite builtin example is the ‘yesno’ tag. Add it to the end of a boolean data, it will print stop printing ‘true’ or ‘false’, will now print ‘yes’ or ‘no’,

<div>
  {{ friend.is_moonim|yesno }}
</div>

The buitin set of tags includes tags for security, number and time formatting, development tools… go look. Quick, a visual website can be made to look close to what an end‐user or customer asks for (even if the end user is yourself). One of the positives of Django is how fast template tags can sketch in visuals related to function.

It is also possible to build custom tags. I’m not going to go into that, but I will point out that there are, through the code of others, many codebases of template tags available. There is reason for that. The ‘yesno’ tag may seem to be a small example. But let’s say you are storing a country of origin on the database. But for the end user you would like to display a visual of a flag? That’s when a template tag called ‘flag’ would be… well… wonderful.

Where to format? The conceptual issue

Some template systems concieve of themselves as Model/View/Controller. Django’s structure can be concieved of as MVC, Model=‘Model’, View=‘View’, Controller=‘various database query filters’, but is not strictly that—and never seems to have been regarded that way. Truth is, Django has a refreshing ‘’get the job done!’ approach.

One place this shows up is in what you can do with templates. Some sytems dislike, and have rigour to avoid, putting ‘logic’ into templates. Templates, they say, are for formatting data into HTML (or maybe JSON etc.) form. If you like, templates are a kind of marshalling. This means that the actions available in a template are limited. You may get a loop structure, to repeat a template, but not much else.

I’m not saying that this rigour isn’t admirable, or worth considering in your project. But I note that Django’s template system is hefty. Let’s take a practical example—you have a boolean value in the database called ‘is_moonim’. It tells you if the object is a ‘Moonim’ or not. You can show this in a template using the ‘yesno tag,

<div>
  {{ friend.is_moonim|yesno }}
</div>

Cute.

But let’s say you’ve decided you want a visual ‘tick’ or ‘cross’ icon instead, and you have these icons in the ‘/static/images’ directory. In Django you can run this logic in the template (I’m pushing ‘static’ in because you’ll usually use it),

{% load static %}
...

{% if friend.is_moonim %}
<img href="{% static '/images/tick.svg" style="icon">
{% else: %}
<img href="{% static '/images/cross.svg" style="icon">
{% endif %]

But you could load this data onto the context in the View itself. I’ll skip the ‘static’ prefix here, because I need to show you ‘mark_safe’. Django escapes all template input, and that needs to be switched off—we know we want to print HTML, not the words of HTML,

from django.utils.safestring import mark_safe

class FriendDetailView(DetailView):
    ...

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        if (self.object.parking_badge):
            context['is_moonim_icon'] = mark_safe('<img href="/static/images/tick.svg" class="icon">')
        else:
            context['is_moonim_icon'] = mark_safe('<img href="/static/images/cross.svg" class="icon">')
        return context

That works no problem. And there is a variant on the template solution also—you could build your own template tag for ‘tickcross’.

Which way do you choose? You’re going to hear a deal of high opinion about this. A few notes—since Django auto‐escapes templates, there’s security in using template logic. Also, the builtin and custom tags are neat. And they tidy visual code away from Views, where the hard logic of summoning querysets and making template choices can be made. But… security is your concern—nobody can complain that Django is not concerned with security. And if you need to do some complex template construction, from multiple calls, then perhaps a View is where to do that. View code is handy for development. And you may be asking where in the end this code should sit. A simple tickbox probably belongs in the template—what if, sometime in the misty future, you call the template from somewhere else? But a device that needs to generate complex, dependant HTML, and may be reused elsewhere, such as Django’s own form generators—that probably will not be in a template. So I give no answer—I show there is a choice.

Refs

Builtin tags. The most evident of these are the structuring tags like ‘for’ and ’if’. But there are also tags to, for example, turn a boolean into the text ‘yes’/‘no’,

https://docs.djangoproject.com/en/3.2/ref/templates/builtins/#cycle

If you want to do something clever with images, or your own formatting, you can write your own tags,

https://docs.djangoproject.com/en/3.2/howto/custom-template-tags/

CSS and JavaScript

CSS is the classic way of modifying the look of a webpage. Mostly, unlike tags, CSS can’t modify the content of what is rendered. But it can transform the look, and is reusable and portable.

As for JS (JavaScript), I suppose most people would say it makes all things possible, Javascript is at it’s most intricate in sourcing new information from the web, or pushing given information to a server.

CDN or not

Or, Content Delivery Network. What I mean is, you can download large, generic lumps of code through the web, not by delivering them from a website server. This is not the place to explore CDN, but I’ll note that for stock CSS and JS components you may wish to use a CDN. A CDN is likely about twice the speed of your Django instance server, will not cost anything (not for stock CSS and JS), and is probably more reliably served across multiple points of delivery. That said, for CSS and JS, serving may only be a small part of serve times (images far outweigh minimal CSS serves) and CSS/JS files delivered through the server can be tuned to your own wishes. So there are arguments both ways.

Add local CSS/JS

To include the base code in a webpage (and ignoring the complexities of Javascript triggering and effect), you need the files of code. Place these files in two folders ‘sitename/static/css’ and/or ‘sitename/static/js’,

mkdir -p sitename/static/css
mkdir -p sitename/static/js

Then link to CSS/JS in templates like this. Note assuming ‘static’, see previous steps,

{% load static %}
    ...
    <link rel="stylesheet" type="text/css" href="{% static 'css/soundsense.css' %}">
    <script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>