vincentf
vincentf

Reputation: 1499

get_context_data in mixin not being called

I'm new to Django. I want to use a mixin to return some data to multiple class based views. It seems the get_context_data I defined in mixin is not called in the view class.

class MyMixin(object):
    def get_context_data(self, *args, **kwargs):
        data = super(MyMixin, self).get_context_data(*args, **kwargs)
        from django.utils import timezone
        data['object'].now = timezone.now()
        return data

class PageDetail(DetailView, MyMixin):
    model = MyModel
    template_name = 'page-detail.html'

    def get_context_data(self, *args, **kwargs):
        data = super(PageDetail, self).get_context_data(*args, **kwargs)
        return data

Upvotes: 3

Views: 913

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476967

You define the base classes in the wrong order:

class PageDetail(DetailView, MyMixin):
    # ...

means that the method resolution order (MRO) is defined as:

>>> PageDetail.__mro__
(<class 'PageDetail'>,
 <class 'django.views.generic.detail.DetailView'>,
 <class 'django.views.generic.detail.SingleObjectTemplateResponseMixin'>,
 <class 'django.views.generic.base.TemplateResponseMixin'>,
 <class 'django.views.generic.detail.BaseDetailView'>,
 <class 'django.views.generic.detail.SingleObjectMixin'>,
 <class 'django.views.generic.base.ContextMixin'>,
 <class 'django.views.generic.base.View'>,
 <class 'MyMixin'>,
 <class 'object'>)

So that means that if we follow the super(PageDetail, self).get_context_data(*args, **kwargs), this will never reach MyMixin, since the ContextMixin defines this as:

class ContextMixin:

    def get_context_data(self, **kwargs):
        if 'view' not in kwargs:
            kwargs['view'] = self
        if self.extra_context is not None:
            kwargs.update(self.extra_context)
        return kwargs

and thus does not call any super() method.

You should define your PageDetail as:

class PageDetail(MyMixin, DetailView):
    # ...

So now the MRO is defined as:

>>> PageDetail.__mro__
(<class 'PageDetail'>,
 <class 'MyMixin'>,
 <class 'django.views.generic.detail.DetailView'>,
 <class 'django.views.generic.detail.SingleObjectTemplateResponseMixin'>,
 <class 'django.views.generic.base.TemplateResponseMixin'>,
 <class 'django.views.generic.detail.BaseDetailView'>,
 <class 'django.views.generic.detail.SingleObjectMixin'>,
 <class 'django.views.generic.base.ContextMixin'>,
 <class 'django.views.generic.base.View'>,
 <class 'object'>)

and thus the super(PageDetail, self).get_context_data(*args, **kwargs) will call the get_context_data of the MyMixin class, which then will call the method next in the MRO.

Upvotes: 6

Related Questions