{{ post.title }}
{{ post.created_at|date:"M d, Y" }}
{{ post.body|truncatewords:30 }}
Build HTML pages with Django's template language. Inheritance with extends/blocks, reusable includes, and built-in filters.
Don't repeat your navbar and footer on every page. Define a base template once and extend it everywhere.
{% block title %}My Blog{% endblock %}
{% block content %}
{% endblock %}
{% include 'partials/footer.html' %}
{% extends 'base.html' %}
{% block title %}Blog Posts{% endblock %}
{% block content %}
All Posts
{% for post in posts %}
{{ post.title }}
{{ post.created_at|date:"M d, Y" }}
{{ post.body|truncatewords:30 }}
{% empty %}
No posts yet.
{% endfor %}
{% endblock %}{{ value|upper }} → UPPERCASE
{{ value|lower }} → lowercase
{{ date|date:"M d, Y" }} → Jan 01, 2026
{{ body|truncatewords:30 }} → first 30 words...
{{ body|truncatechars:100 }} → first 100 chars...
{{ body|linebreaks }} → tags from newlines
{{ value|default:"N/A" }} → fallback if falsy
{% url 'view_name' %} tag generates URLs from named views. Never hardcode URLs in templates. If you change the URL pattern, the template still works because it looks up by name.{% extends 'base.html' %} + {% block content %}{% endblock %} = DRY templates.{% url 'name' %} generates URLs. Never hardcode. {% include 'partial.html' %} inserts snippets.|date, |truncatewords, |upper, |default.{% for item in list %}{% empty %}{% endfor %} — the empty block handles empty lists gracefully.