Django Templates
Downloaded from PrepIQ (https://prepiq.online)
Q1. What is the Django Template Language (DTL) and how does it differ from plain Python?
DTL is a restricted, designer-friendly templating syntax embedded in HTML files, intentionally limited so templates stay simple and separated from complex business logic.
# book_list.html
<h1>Books</h1>
<ul>
{% for book in books %}
<li>{{ book.title }} - ${{ book.price }}</li>
{% empty %}
<li>No books available</li>
{% endfor %}
</ul>
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}!</p>
{% else %}
<p>Please log in</p>
{% endif %}| DTL restriction | Why it exists |
|---|---|
| No arbitrary Python expressions ({{ x + y }} works only for simple cases via filters) | Keeps templates safe for non-programmers (designers) to edit |
| No function calls with arguments directly | Prevents complex logic from leaking into presentation layer |
| Dot notation (.) accesses attributes, dict keys, AND method calls uniformly | Simplifies syntax - {{ obj.attr }} works whether attr is a field, method, or dict key |
# {{ book.title }} tries, in order:
# 1. book['title'] (dictionary lookup)
# 2. book.title (attribute lookup)
# 3. book.title() (method call, if title is callable)
# 4. book[0] (numeric index, if title is a number)
# Rendering a template from a view
from django.shortcuts import render
def book_list(request):
books = Book.objects.all()
return render(request, 'book_list.html', {'books': books, 'page_title': 'All Books'})
Q2. What is template inheritance in Django and how do {% extends %} and {% block %} work?
Template inheritance lets a base template define the overall page structure, with child templates overriding specific sections (blocks) - avoiding repeated HTML boilerplate across pages.
# base.html - defines the overall structure
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Site{% endblock %}</title>
{% block extra_head %}{% endblock %}
</head>
<body>
<nav>{% include 'navbar.html' %}</nav>
<main>
{% block content %}
<p>Default content</p>
{% endblock %}
</main>
<footer>© 2024</footer>
</body>
</html>
# book_list.html - extends base.html, overrides specific blocks
{% extends 'base.html' %}
{% block title %}Books - My Site{% endblock %}
{% block content %}
<h1>Book List</h1>
<ul>
{% for book in books %}
<li>{{ book.title }}</li>
{% endfor %}
</ul>
{% endblock %}
# {% extends %} MUST be the first tag in the template
# Any content OUTSIDE a {% block %} in a child template is IGNORED
# Accessing the parent block's content with {{ block.super }}
{% block content %}
{{ block.super }} <!-- includes whatever was in the parent's block first -->
<p>Additional content specific to this page</p>
{% endblock %}
# Multi-level inheritance is also possible:
# base.html -> app_base.html (extends base.html) -> book_list.html (extends app_base.html)
Q3. What is the difference between {% include %} and {% extends %} in Django templates?
| Tag | Purpose | Relationship |
|---|---|---|
| {% extends %} | Inherit a parent template's structure, override blocks | Child-parent (one template extends another) |
| {% include %} | Insert another template's content directly at that point | Composition (embedding a reusable fragment) |
# navbar.html - a reusable fragment
<nav>
<a href='/'>Home</a>
<a href='/books/'>Books</a>
{% if user.is_authenticated %}
<a href='/logout/'>Logout</a>
{% endif %}
</nav>
# base.html uses include to embed the fragment
<body>
{% include 'navbar.html' %}
{% block content %}{% endblock %}
</body>
# Passing extra context to an included template
{% include 'book_card.html' with book=featured_book highlight=True %}
# only=True limits the included template to ONLY the passed variables,
# not the full surrounding context
{% include 'book_card.html' with book=featured_book only %}
# A template can use BOTH extends and include together
# page.html
{% extends 'base.html' %}
{% block content %}
{% include 'book_card.html' with book=book %}
{% endblock %}
# KEY DIFFERENCE: extends is about INHERITING a page's overall layout
# (one per template, must be the first tag); include is about REUSING
# a fragment (can be used multiple times, anywhere in the template)
Q4. What are Django template filters and how do you create a custom filter?
Filters transform a variable's displayed value using the pipe (|) syntax. Django ships with many built-in filters, and custom ones can be registered for app-specific formatting needs.
{{ book.title|upper }} <!-- UPPERCASE -->
{{ book.title|lower }} <!-- lowercase -->
{{ book.title|truncatewords:5 }} <!-- first 5 words -->
{{ book.price|floatformat:2 }} <!-- 25.99 -->
{{ book.description|default:'No description' }} <!-- fallback if empty/falsy -->
{{ book.description|striptags }} <!-- removes HTML tags -->
{{ books|length }} <!-- count of items -->
{{ book.published_date|date:'F j, Y' }} <!-- January 1, 2024 -->
# Chaining filters - applied left to right
{{ book.title|lower|truncatewords:3 }}
# CUSTOM FILTER - defined in a templatetags module
# myapp/templatetags/__init__.py (empty file)
# myapp/templatetags/custom_filters.py
from django import template
register = template.Library()
@register.filter(name='currency')
def currency(value):
return f'${value:,.2f}'
@register.filter
def discount(value, percent): # filters can take ONE argument
return value * (1 - percent / 100)
# Using the custom filter in a template
{% load custom_filters %} <!-- must load the module first -->
<p>{{ book.price|currency }}</p> <!-- $25.99 -->
<p>{{ book.price|discount:10|currency }}</p> <!-- 10% off, then formatted -->
# is_safe and needs_autoescape - important flags for filters that
# return HTML, to control Django's automatic escaping behavior
@register.filter(is_safe=True)
def bold_title(value):
from django.utils.safestring import mark_safe
return mark_safe(f'<strong>{value}</strong>')
Q5. How does Django's automatic HTML escaping work, and how do you disable it safely?
Django automatically escapes special HTML characters in template variables to prevent Cross-Site Scripting (XSS) attacks, converting characters like <, >, and & into their safe HTML entity equivalents.
# If a book title contains user-submitted HTML/script content:
# book.title = '<script>alert("XSS")</script>'
{{ book.title }}
<!-- Rendered as literal text, NOT executed:
<script>alert("XSS")</script> -->
# Disabling escaping for a SPECIFIC trusted value with the safe filter
{{ trusted_html_content|safe }}
<!-- Only use this for content YOU control or have sanitized -->
# Disabling escaping for an entire block
{% autoescape off %}
{{ trusted_content }}
{% endautoescape %}
# Marking a string as safe in Python code (use with extreme caution)
from django.utils.safestring import mark_safe
def render_bold(text):
return mark_safe(f'<strong>{text}</strong>')
# DANGEROUS if 'text' contains unsanitized user input - only mark_safe()
# content that is fully controlled or has been properly sanitized
# format_html() - safer way to build HTML with dynamic values,
# automatically escapes the ARGUMENTS while keeping the template safe
from django.utils.html import format_html
def render_book_link(book):
return format_html('<a href="{}">{}</a>', book.get_absolute_url(), book.title)
# book.title is automatically escaped even though the surrounding HTML isn't
# NEVER do this - defeats escaping entirely and is a classic XSS vulnerability:
# return mark_safe(f'<a href="{url}">{user_provided_title}</a>')
Q6. How do you use {% for %} loops with additional variables like forloop.counter?
Inside a {% for %} loop, Django provides a special forloop variable exposing metadata about the current iteration - position, first/last flags, and parent loop access for nested loops.
<ul>
{% for book in books %}
<li>
{{ forloop.counter }}. {{ book.title }}
{% if forloop.first %}(First!){% endif %}
{% if forloop.last %}(Last!){% endif %}
</li>
{% endfor %}
</ul>
<!-- forloop attributes available:
forloop.counter - 1-indexed iteration count (1, 2, 3, ...)
forloop.counter0 - 0-indexed iteration count (0, 1, 2, ...)
forloop.revcounter - counts DOWN to 1
forloop.revcounter0 - counts DOWN to 0
forloop.first - True on the first iteration
forloop.last - True on the last iteration
forloop.parentloop - access the outer loop's forloop, in nested loops -->
<!-- Nested loop example using forloop.parentloop -->
{% for author in authors %}
<h3>{{ author.name }}</h3>
<ul>
{% for book in author.books.all %}
<li>{{ forloop.parentloop.counter }}.{{ forloop.counter }} {{ book.title }}</li>
{% endfor %}
</ul>
{% endfor %}
<!-- {% empty %} - fallback content when the QuerySet/list is empty -->
{% for book in books %}
<li>{{ book.title }}</li>
{% empty %}
<li>No books found</li>
{% endfor %}
<!-- Applying alternating row styles using forloop.counter -->
{% for book in books %}
<tr class='{% cycle "row-odd" "row-even" %}'>
<td>{{ book.title }}</td>
</tr>
{% endfor %}
Q7. What are Django context processors and how do they work?
Context processors are functions that add variables to the context of EVERY template rendered with RequestContext (which render() uses by default), avoiding the need to manually pass common data in every view.
# settings.py - built-in context processors registered by default
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', # adds 'user'
'django.contrib.messages.context_processors.messages', # adds 'messages'
],
},
},
]
# Because of auth's context processor, {{ user }} is available in
# EVERY template automatically - you never manually pass 'user' from views
# CUSTOM context processor - myapp/context_processors.py
def site_settings(request):
return {
'site_name': 'My Bookstore',
'current_year': 2024,
}
def cart_info(request):
if request.user.is_authenticated:
count = request.session.get('cart_count', 0)
else:
count = 0
return {'cart_item_count': count}
# Registering the custom processor in settings.py
TEMPLATES = [
{
'OPTIONS': {
'context_processors': [
# ... built-in ones ...
'myapp.context_processors.site_settings',
'myapp.context_processors.cart_info',
],
},
},
]
# Now EVERY template can use these without views passing them explicitly
# base.html
<footer>{{ site_name }} © {{ current_year }}</footer>
<span>Cart: {{ cart_item_count }}</span>
# Note: context processors only run for templates rendered via
# render() or RequestContext - not for Template().render(Context()) directly
Q8. How do you serve static files and media files in Django?
| Type | Purpose | Settings |
|---|---|---|
| Static files | CSS, JS, images bundled with your app code | STATIC_URL, STATICFILES_DIRS, STATIC_ROOT |
| Media files | User-uploaded content (profile pictures, documents) | MEDIA_URL, MEDIA_ROOT |
# settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static'] # where Django looks in development
STATIC_ROOT = BASE_DIR / 'staticfiles' # where collectstatic gathers files for production
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media' # where uploaded files are stored
# In templates - loading and referencing static files
{% load static %}
<link rel='stylesheet' href="{% static 'css/style.css' %}">
<img src="{% static 'images/logo.png' %}" alt='Logo'>
# Serving media files - referencing an uploaded file via a model field
class Book(models.Model):
cover = models.ImageField(upload_to='book_covers/')
# In a template
<img src="{{ book.cover.url }}" alt="{{ book.title }}">
# urls.py - serving media files during DEVELOPMENT only
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# ... your other patterns ...
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# For PRODUCTION, static/media files should be served by a dedicated
# web server (Nginx) or cloud storage (AWS S3 via django-storages),
# NOT by Django itself - Django serving files directly is slow and
# insecure at scale
# Collecting all static files into STATIC_ROOT for deployment
# $ python manage.py collectstatic
Q9. What is the difference between {% if %} template tag conditions and custom template tags?
{% if %} handles simple conditional logic with built-in comparison operators, while custom template tags let you encapsulate more complex, reusable logic that goes beyond simple filters.
<!-- {% if %} supports comparison operators directly -->
{% if book.price > 50 %}
<span class='expensive'>Premium</span>
{% elif book.price > 20 %}
<span class='mid'>Standard</span>
{% else %}
<span class='budget'>Budget</span>
{% endif %}
<!-- Logical operators: and, or, not, in, not in -->
{% if book.available and book.price < 30 %}
<button>Buy Now</button>
{% endif %}
{% if user in book.wishlisted_by.all %}
<span>In your wishlist</span>
{% endif %}
<!-- CUSTOM SIMPLE TAG - for logic beyond what {% if %}/filters can express -->
# myapp/templatetags/book_tags.py
from django import template
register = template.Library()
@register.simple_tag
def discounted_price(price, percent):
return price * (1 - percent / 100)
# Usage in template
{% load book_tags %}
{% discounted_price book.price 20 as sale_price %}
<p>Sale price: ${{ sale_price|floatformat:2 }}</p>
<!-- CUSTOM INCLUSION TAG - renders its own mini-template -->
@register.inclusion_tag('book_card.html')
def show_book_card(book):
return {'book': book, 'discount_available': book.price > 50}
<!-- Usage -->
{% show_book_card featured_book %}
<!-- Django renders book_card.html with the returned context automatically -->
<!-- Rule of thumb: use {% if %} for simple presentational conditions,
custom tags when logic is complex or reused across many templates -->
Q10. What is the {% with %} tag used for in Django templates?
{% with %} caches a complex expression (like a chained lookup or method call) into a simple variable name for the duration of a block, avoiding repeated evaluation and improving readability.
<!-- WITHOUT {% with %} - the expensive expression is evaluated MULTIPLE times -->
<p>{{ book.author.profile.bio|truncatewords:20 }}</p>
<p>By {{ book.author.profile.full_name }}</p>
<p>Contact: {{ book.author.profile.email }}</p>
<!-- book.author.profile is resolved three separate times -->
<!-- WITH {% with %} - resolved ONCE, reused via a short name -->
{% with profile=book.author.profile %}
<p>{{ profile.bio|truncatewords:20 }}</p>
<p>By {{ profile.full_name }}</p>
<p>Contact: {{ profile.email }}</p>
{% endwith %}
<!-- Multiple variables in one {% with %} -->
{% with total=book.price count=book.reviews.count %}
<p>${{ total }} ({{ count }} reviews)</p>
{% endwith %}
<!-- Practical use case: caching a queryset method call result
that would otherwise hit the database multiple times -->
{% with recent_reviews=book.reviews.all|slice:':5' %}
<p>{{ recent_reviews|length }} recent reviews</p>
{% for review in recent_reviews %}
<p>{{ review.text }}</p>
{% endfor %}
{% endwith %}
<!-- Note: {{ variable_name }} lookups themselves are relatively cheap in
Django templates (no repeated DB hits for simple attribute access),
but {% with %} is valuable when the expression involves a method
call, filter, or QuerySet evaluation that would otherwise repeat -->
<!-- Scope: variables defined in {% with %} are ONLY available inside
the {% with %}...{% endwith %} block, not outside it -->
Django Templates
What is the Django Template Language (DTL) and how does it differ from plain Python?
DTL is a restricted, designer-friendly templating syntax embedded in HTML files, intentionally limited so temp...
What is template inheritance in Django and how do {% extends %} and {% block %} work?
Template inheritance lets a base template define the overall page structure, with child templates overriding s...
What is the difference between {% include %} and {% extends %} in Django templates?
TagPurposeRelationship{% extends %}Inherit a parent template's structure, override blocksChild-parent (one tem...
What are Django template filters and how do you create a custom filter?
Filters transform a variable's displayed value using the pipe (|) syntax. Django ships with many built-in filt...
How does Django's automatic HTML escaping work, and how do you disable it safely?
Django automatically escapes special HTML characters in template variables to prevent Cross-Site Scripting (XS...
How do you use {% for %} loops with additional variables like forloop.counter?
Inside a {% for %} loop, Django provides a special forloop variable exposing metadata about the current iterat...
What are Django context processors and how do they work?
Context processors are functions that add variables to the context of EVERY template rendered with RequestCont...
How do you serve static files and media files in Django?
TypePurposeSettingsStatic filesCSS, JS, images bundled with your app codeSTATIC_URL, STATICFILES_DIRS, STATIC_...
What is the difference between {% if %} template tag conditions and custom template tags?
{% if %} handles simple conditional logic with built-in comparison operators, while custom template tags let y...
What is the {% with %} tag used for in Django templates?
{% with %} caches a complex expression (like a chained lookup or method call) into a simple variable name for...