Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django CBV - How to avoid repeating the get_context_data for every view just to get a custom title?

I'm setting a {{ title }} for every page of my project. Sometimes this title is a static string such as Enter your Name and sometimes it's based on a relevant object on that page, such as Employee.first_name.

To create context['title'], I'm using get_context_data inside every class based view. But this seems to be resulting in me repeating a chunk of code every time, and I'm looking to reduce that somehow.

For example to write a custom title for each page, I'd have to write this:

def get_context_data(self, **kwargs):
    context = super(SomeView, self).get_context_data(**kwargs)
    context['title'] = 'Title for This page'
    return context

I feel like it'd be ideal to have a mixin that I somehow just pass in the variable for title and my context dictionary will automatically have context['title'] added based on the passed in variable.

Is this possible? Is there a way to create a mixin such that all I have to do is pass in a variable, and it'll give me a context just for the title instead of writing out that chunk of code for every single view?

like image 343
Garfonzo Avatar asked Aug 25 '15 15:08

Garfonzo


2 Answers

Yes, it's possible and easy:

class YourTitleMixin(object):
    title = None # or your default title if you won't provide any

    def get_title(self):
        return self.title

    def get_context_data(self, **kwargs):
        context= super(YourTitleMixin, self).get_context_data(**kwargs)
        context['title'] = self.get_title()
        return context

And you use it:

def YourPageView(YourTitleMixin, DetailView):
    title = "Your Page Title" # you can either use this ...

    def get_title(self):
        return self.get_object().name # ... or that, if your title should be generated from some data

But is this necessary? Are you using your title only once in template? Do you share one template between views? Maybe you can do it purely in your templates? For example:

{# base.html #}
<html>
  <head>
    <title>{% block page_title %}My page{% endblock %}</title>
  </head>
</html>

{# detail.html #}
{% extends "base.html" %}
{% block title %}{{ article.name }} - {{ block.super }}{% endblock %}
{# will result in "article name - My Page". You don't need to use super if you don't want to #}
like image 164
GwynBleidD Avatar answered Sep 30 '22 17:09

GwynBleidD


I usually solve this with a mixin:

class TitleMixin(object):
    """Pass a defined title to context"""

    title = None

    def get_title(self):
        return self.title

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = self.get_title()

        return context

In you views, you can then do:

class BlogIndex(TitleMixin, ListView):
    title = 'Blog entries'

class EntryDetail(TitleMixin, DetailView)
    def get_title(self): # for dynamic title, such as coming from a model field
        return self.object.title
like image 40
Agate Avatar answered Sep 30 '22 17:09

Agate