Skip to content

3. Advance Templates

In Django, templates are used to separate the HTML and business logic of an application. They allow for rendering dynamic data into static HTML, helping to keep the view layer clean and maintainable. Advanced Django template usage involves leveraging template inheritance, custom filters, tags, context processors, and more.

1. Template Inheritance

Template inheritance is one of the most powerful features of Django templates. It allows you to create a base template that contains common elements like headers, footers, and navigation, and then extend that base template in child templates.

Base Template (base.html)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}My Site{% endblock %}</title>
</head>
<body>
<header>
<h1>Welcome to My Site</h1>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about/">About</a></li>
<li><a href="/contact/">Contact</a></li>
</ul>
</nav>
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
<p>&copy; 2025 My Site</p>
</footer>
</body>
</html>

Child Template (home.html)

{% extends "base.html" %}
{% block title %}Home - My Site{% endblock %}
{% block content %}
<h2>Welcome to the Home Page</h2>
<p>This is where the content of the home page goes.</p>
{% endblock %}
  • Explanation:
    • The base.html contains the structure that is common to all pages (header, footer, navigation).
    • The home.html extends base.html, overriding the title and content blocks to provide page-specific content.

2. Custom Template Filters

Django allows you to define custom template filters to apply logic directly in the template. For instance, you could create a filter to format dates or numbers in a specific way.

Custom Filter Example

Create a custom filter in a file called templatetags/custom_filters.py:

custom_filters.py
from django import template
import datetime
register = template.Library()
@register.filter
def format_date(value, date_format='%Y-%m-%d'):
if isinstance(value, datetime.date):
return value.strftime(date_format)
return value

Using the Custom Filter in Templates

In your template, you need to load the custom filter before using it:

{% load custom_filters %}
<p>Today’s date: {{ today|format_date:"%B %d, %Y" }}</p>
  • Explanation:
    • format_date is a custom filter that takes a date and formats it according to the specified date_format.
    • In the template, today (which is expected to be a datetime.date object) will be formatted using the custom filter.

3. Custom Template Tags

In addition to filters, you can define custom template tags that allow you to execute more complex logic within the template. For example, a custom tag to display the latest posts from a blog:

Custom Tag Example

Create a custom tag in templatetags/blog_tags.py:

blog_tags.py
from django import template
from blog.models import Post
register = template.Library()
@register.simple_tag
def latest_posts(count=5):
return Post.objects.all().order_by('-created_at')[:count]

Using the Custom Tag in Templates

In your template, load the custom tag and use it:

{% load blog_tags %}
<h2>Latest Posts</h2>
<ul>
{% latest_posts 5 as posts %}
{% for post in posts %}
<li>{{ post.title }} - {{ post.created_at|date:"F d, Y" }}</li>
{% endfor %}
</ul>
  • Explanation:
    • The latest_posts custom tag retrieves the latest posts from the database and returns a queryset.
    • We use the {% latest_posts 5 as posts %} syntax to assign the latest posts to a variable posts, which is then looped through to display the post titles.

4. Template Context Processors

Context processors are functions that return a dictionary of context data that is available globally to all templates. You can use context processors to provide site-wide data, such as user information, site settings, or common data that should be accessible across your application.

Creating a Context Processor

In context_processors.py:

context_processors.py
from django.conf import settings
def site_settings(request):
return {
'site_name': settings.SITE_NAME,
'admin_email': settings.ADMIN_EMAIL,
}

Register the Context Processor in settings.py

settings.py
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',
'yourapp.context_processors.site_settings', # Add this line
],
},
},
]

Using Context Data in Templates

Now, the site_name and admin_email values will be available in all templates:

<h1>Welcome to {{ site_name }}</h1>
<p>For inquiries, please contact {{ admin_email }}</p>
  • Explanation:
    • The site_settings context processor makes site_name and admin_email available in all templates.
    • This is useful for global settings like the site name or admin email that are needed across multiple templates.

5. Template Includes for Reusable Components

You can break up your templates into smaller, reusable components using the {% include %} tag. This is useful for elements like navigation bars, footers, or repeated UI components.

Reusable Component (nav.html)

nav.html
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about/">About</a></li>
<li><a href="/contact/">Contact</a></li>
</ul>
</nav>

Including the Component in Other Templates

base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}My Site{% endblock %}</title>
</head>
<body>
{% include 'nav.html' %}
{% block content %}{% endblock %}
</body>
</html>
  • Explanation:
    • The nav.html file contains the markup for the navigation menu.
    • The {% include 'nav.html' %} tag in base.html allows you to include the navigation bar in multiple templates.

6. Template for Dynamic Forms

You can render dynamic forms in templates, making them flexible and reusable.

Form Definition in forms.py

from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length=100)
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea)

Rendering the Form in a Template

contact.html
<h2>Contact Us</h2>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
  • Explanation:
    • The form is rendered dynamically using {{ form.as_p }}, which renders each form field inside a <p> tag. You can also use other render options like {{ form.as_table }} or manually loop over form fields.