It's easy to forget about the HTML <title>
element when building a Django app.
You put one in your base.html
when you start the project,
but forget to actually change the title when making your individual views and templates.
<!doctype html>
<html lang="en">
<head>
<title>Forge</title>
</head>
But good page titles are incredibly useful!
Forgetting them can hurt both SEO and user experience.
There are two ways we recommend implementing HTML page titles in Django:
- Using template blocks (simpler)
- Using class-based views (more powerful)
Django page titles using template blocks
Template blocks can be used for small pieces of content just like they can be used for entire headers/bodies/footers.
In your base.html
, use a standard template block inside the <title>
tag:
<!doctype html>
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
</head>
When you extend your template,
simply use the {% block title %}
to set the page title:
{% extends "base.html" %}
{% block title %}Billing{% endblock %}
{% block content %}
...
{% endblock %}
You can use context variables just like any other template blocks:
{% extends "base.html" %}
{% block title %}{{ obj.name }} billing{% endblock %}
{% block content %}
...
{% endblock %}
That's all there is to it!
If you don't know where to start then give this a try.
But if you find yourself needing more control then consider moving the logic to your Django views instead...
Django page titles using class-based views
In Forge, we strongly prefer class-based views over function-based views.
One reason is because it's much easier to share logic across your views, often across your entire app.
Generating page titles is a good example of how this can be useful.
Let's create a view mixin with a page title feature that injects a title
variable into the template context:
class PageTitleViewMixin:
title = ""
def get_title(self):
"""
Return the class title attr by default,
but you can override this method to further customize
"""
return self.title
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = self.get_title()
return context
Then use {{ title }}
in your base.html
:
<!doctype html>
<html lang="en">
<head>
<title>{{ title }}</title>
</head>
By using both a title
class attribute and a get_title
method,
it will be easy to set a "static" title for a view:
class BillingView(PageTitleViewMixin, TemplateView):
template_name = "billing.html"
title = "Billing"
But also do something more dynamic:
class ProjectView(PageTitleViewMixin, DetailView):
def get_title(self):
return self.object.name
You could further extend this to add a suffix to the title automatically:
class PageTitleViewMixin:
...
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = self.get_title() + " - My App"
return context
Bonus! You could also raise an exception on empty titles,
so you don't forget to set the title for every view:
class PageTitleViewMixin:
...
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
title = self.get_title()
if not title:
raise ValueError("Page title should not be empty")
context["title"] = title + " - My App"
return context
Top comments (0)