18

I constantly see myself having to add the same extra variable to the context of many of my views.

def get_context_data(self, **kwargs):
    # Call the base implementation first to get a context
    context = super(MyListView, self).get_context_data(**kwargs)
    # Add in the house
    context['house'] = self.get_object().house
    return context

As I don't like repeating myself, I thought I could create a new class extending the view, and then I could base all my views on the new extended view class. The thing is, there are 4 classes of views I use: CreateView, UpdateView, ListView, and DeleteView. Do I really have to create a new class for each one of them?

Isn't there something like a Django "base" view class? Maybe a smarter way to do this?

Clash
  • 4,896
  • 11
  • 47
  • 67
  • This is a potential solution although I'm not sure i'm all that keen on it - http://reinout.vanrees.org/weblog/2014/05/19/context.html – rix May 20 '14 at 12:46

1 Answers1

23

Create a Mixin:

from django.views.generic.base import ContextMixin

class HouseMixin(ContextMixin):
  def get_house(self):
    # Get the house somehow
    return house

  def get_context_data(self, **kwargs):
    ctx = super(HouseMixin, self).get_context_data(**kwargs)
    ctx['house'] = self.get_house()
    return ctx

Then in your other classes you'd use multiple inheritance:

class HouseEditView(HouseMixin, UpdateView):
  pass

class HouseListView(HouseMixin, ListView):
  pass

and so on, then all these views will have house in the context.

Algorithmatic
  • 1,824
  • 2
  • 24
  • 41
Jj.
  • 3,160
  • 25
  • 31
  • 3
    Wow this actually worked! I thought super(HouseMixin, self).get_context_data(**kwargs) would return an error, because the super of HouseMixin is object and object has not defined get_context_data. Can you explain to me as to why it works? – Clash Apr 26 '12 at 18:10
  • 3
    It works as long as one of the parent classes implements the method, if none did, it would raise an Error. So this mixin is designed to be mixed with any Django view that also implements .get_context_data(). – Jj. Apr 26 '12 at 18:26
  • 1
    does this have to do with the order the classes are extended? i.e HouseMixin, UpdateView instead of UpdateView, HouseMixin – Clash Apr 26 '12 at 18:41
  • 2
    Yes, the order of parent classes affects the MRO, read a SO answer with a link to its history here: http://stackoverflow.com/a/3277407/43490 – Jj. Apr 26 '12 at 18:54
  • I had troubles with mixins and url reversing until I've changed the order of arguments within class definitions, e.g. `class MyListView(ListView, BaseContextMixin):`. Django 1.5.5, Python 2.7.5. – Geradlus_RU Nov 12 '13 at 08:41
  • What if `get_house()` is a method that depends on the `request`? For example, if I needed to get a house instance based on `request.user`? – Algorithmatic Jun 07 '16 at 18:13
  • 1
    Nevermind, I got it. You just need to do `class HouseMixin(ContextMixin, View)` instrad – Algorithmatic Jun 07 '16 at 18:18