04 April 2020

Often in a web application/website, you want each page or view to have a title that semantically describes what the current page is showing. In a web application, these may be dynamic titles, based on some attribute of the primary model being displayed on the page. I recently encountered this problem while working on the new version of Seeker, but I did not find that many appealing solutions through my usual Google/StackOverflow search. After a little bit of thought and trial and error, I ended up coming with a pretty good mixin-based solution.

First, you should make a base.html file that all your other templates inherit from and add the following to the <head></head> section.

<!-- Assuming this is in a template called `base.html` that gets inherited by other templates --> <title> {{page_title}} </title>

This is saying that whatever exists at the page_title attribute in the context object will be the title of the page. Now, let’s create a mixin for our views that will set this page_title attribute.

class PageTitleMixin ( object ): def get_page_title ( self , context ): return getattr ( self , "page_title" , "Default Page Title" ) def get_context_data ( self , ** kwargs ): context = super () . get_context_data ( ** kwargs ) context [ "page_title" ] = self . get_page_title ( context ) return context

This gives us two ways of defining a page title for our views that use this mixin.

Define a page_title attribute on the class. Override get_page_title to dynamically set the page title.

Now that we got this mixin defined, let’s actually use it.

# Renders "Static Page Title" as the page title class StaticPageTitleView ( PageTitleMixin , View ): template_name = "index.html" page_title = "Static Page Title" # Renders "Default Page Title" as the page title class DefaultPageTitleView ( PageTitleMixin , View ): template_name = "index.html" # Renders "Some Model Attr" as the page title class DynamicPageTitleView ( PageTitleMixin , DetailView ) template_name = "index.html" model = OurModel # assume that it has an attribute called `title` context_object_name = "model" def get_page_title ( self , context ): return context [ "model" ] . title # Assume this returns "Some Model Attr"

Lastly, let’s say you have another mixin that dynamically populates the context and you want to use that as the default value. That’s possible too, we just need to make some minor tweaks to our mixin code. Check this out.

class PageTitleMixin ( object ): def get_page_title ( self , context ): return getattr ( self , "page_title" , context [ "user_settings" ] . site_title ) def get_context_data ( self , ** kwargs ): context = super () . get_context_data ( ** kwargs ) context [ "page_title" ] = self . get_page_title ( context ) return context # We want to inject the `user_settings`object into every single context. class UserSettingsContextMixin ( object ): def get_context_data ( self , ** kwargs ): context = super () . get_context_data ( ** kwargs ) user = self . request . subdomain_user # assume the user has a settings object with a title attribute context [ "user_settings" ] = user . settings return context # Use another mixin to encapsulate all mixins for our page. class PageMixin ( PageTitleMixin , UserSettingsContextMixin ): pass # Renders "Some User's Title" as the page title class DefaultPageTitleView ( PageMixin , View ): template_name = "index.html"