How to generate dynamic HTML with Django templates in Python

How to generate dynamic HTML with Django templates in Python

Django’s template engine is deceptively simple on the surface, but it packs a punch when it comes to generating dynamic HTML content. It’s designed to keep the presentation layer cleanly separated from the business logic, which means your HTML stays readable and your Python code stays maintainable.

At its core, the template engine is a text substitution system. You write templates with placeholders, and Django replaces those placeholders with actual data at runtime. The placeholders come in two flavors: variables and tags. Variables are basically Python expressions that output values, while tags are more like mini-programs—they control the logic and flow inside your template.

One of the keys to mastering Django templates is understanding the context. When you render a template, you pass in a context dictionary—a mapping of variable names to Python objects. This context is the sandbox where the template plays. Every variable you reference inside the template has to come from this context, or else Django will throw an error or silently render an empty string.

Here’s the simplest example to get you started:

from django.shortcuts import render

def my_view(request):
    context = {
        'name': 'Jeff',
        'items': ['apple', 'banana', 'cherry'],
    }
    return render(request, 'my_template.html', context)

And the corresponding template snippet (my_template.html) might look like this:

<p>Hello, {{ name }}!</p>
<ul>
{% for item in items %}
  <li>{{ item }}</li>
{% endfor %}
</ul>

Notice how the {{ name }} syntax lets you inject simple variables, while the {% for %} tag enables looping over lists. This separation keeps your templates concise and free from the clutter of raw Python code.

But what about escaping? Django templates automatically escape variables to prevent XSS attacks, which is a blessing and sometimes a curse. If you want to output raw HTML, you have to explicitly mark it safe, like this:

from django.utils.safestring import mark_safe

def my_view(request):
    raw_html = '<strong>Important!</strong>'
    context = {'message': mark_safe(raw_html)}
    return render(request, 'my_template.html', context)

And in the template:

<p>Message: {{ message }}</p>

Without using mark_safe, Django would escape the tags and you’d see them rendered literally in the browser.

Another subtlety is the lazy evaluation of template variables. The template engine will only evaluate variables when rendering, so you can pass complex objects in the context and use their properties or methods selectively. For example, if you have a User object, you can do:

<p>Welcome, {{ user.get_full_name }}!</p>

Keep in mind that methods called in templates should be side-effect free and quick because templates are meant to stay fast and non-intrusive.

Finally, Django’s template system supports template inheritance, which lets you build a base template with common layout and extend it in child templates to override specific blocks of content. This keeps your templates DRY and modular:

<!-- base.html -->
<html>
  <head><title>My Site</title></head>
  <body>
    {% block content %}{% endblock %}
  </body>
</html>

<!-- home.html -->
{% extends "base.html" %}

{% block content %}
  <h1>Welcome home!</h1>
{% endblock %}

This inheritance model is the backbone of large Django projects where consistency and maintainability matter.

Understanding these basics will give you the confidence to write templates that are both powerful and clean. Next, we’ll dive into how template tags and filters let you manipulate data directly in your templates without muddying your views or models—because sometimes you want to format a date or truncate a string right where it’s displayed.

Creating dynamic content with template tags and filters

Template tags in Django allow you to execute logic within your templates, enhancing their functionality beyond simple variable substitution. They act as a bridge between your data and presentation, enabling you to perform actions like loops, conditionals, and even custom operations.

One of the most common use cases for template tags is the {% if %} tag, which lets you conditionally render content based on the value of a variable. Here’s a quick example:

<p>
{% if user.is_authenticated %}
  Welcome back, {{ user.get_full_name }}!
{% else %}
  Please log in.
{% endif %}
</p>

This snippet checks if a user is authenticated and displays a welcome message if they are; otherwise, it prompts them to log in. It’s a straightforward way to control what your users see based on their state.

Another powerful feature is the {% for %} tag, which we’ve already touched on. You can also use it to loop through a dictionary, not just a list. Here’s how:

<ul>
{% for key, value in items.items %}
  <li>{{ key }}: {{ value }}</li>
{% endfor %}
</ul>

This allows you to iterate over key-value pairs, giving you flexibility in how you display data.

Django also comes with a rich set of built-in filters that allow you to modify the output of your variables easily. For instance, the date filter formats date objects. Here’s how you can apply it:

<p>Published on: {{ post.published_date|date:"F j, Y" }}</p>

This would render the date in a more human-readable format, turning something like 2023-10-01 into October 1, 2023.

Filters can be chained as well, enabling you to apply multiple transformations in one go. For example:

<p>{{ some_text|truncatewords:30|upper }}</p>

This takes a string, truncates it to 30 words, and then converts it to uppercase. It’s a concise way to manage content presentation directly in your templates.

If the built-in filters don’t meet your needs, you can create custom filters. To do this, you’ll define a function in your app and register it as a filter. Here’s a quick example:

from django import template

register = template.Library()

@register.filter
def add_suffix(value, suffix):
    return f"{value}{suffix}"

Once registered, you can use your custom filter in the template like this:

<p>{{ item|add_suffix:" is awesome!" }}</p>

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *