### View implementation in a views.py class RelatedMixin(object): relation_chain = None context_list_name = 'related_list' keep_intermediaries = False def get_context_data(self, **kwargs): context = super(RelatedMixin, self).get_context_data(**kwargs) assert hasattr(self, 'object'), "RelatedMixin must be used with a view containing an instance of a model named 'object',\nnormally a subclass of SingleObjectMixin." assert hasattr(self, 'relation_chain'), "RelatedMixin must supply an OrderedDict named 'relation_chain' of fk/queryset tuples honing in on the desired object_list\n(refer to http://djangosnippets.org/snippets/2756/)" ids = [self.object.id] current_qs = not self.keep_intermediaries for fk, qs in self.relation_chain.iteritems(): qs = qs.filter(**{fk+"__in":ids}) ids = qs.only('id') if self.keep_intermediaries: if current_qs: context[fk+"_list"] = current_qs current_qs = qs context['object_list'] = context[self.context_list_name] = qs return context ### Example mixin application from mixins.views import RelatedMixin from django.views.generic import DetailView, UpdateView class DetailRelatedView(RelatedMixin,DetailView): pass class UpdateRelatedView(RelatedMixin,UpdateView): pass ### Example usage in a urls.py from django.conf.urls import patterns, url from extra.views import DetailRelatedView from collections import OrderedDict from organization.models import Company, People, Computers urlpatterns = patterns('organization.views', ## One level deep ## yields 'object'='company' and 'object_list'='related_list' in context url(r'^companies/(?P\d+)/people/$', ShowRelatedView.as_view( template_name="company/related/people.html", model=Company, relation_chain=OrderedDict([('company',People.objects.all())]) ), name='people_for_company' ), ## Two levels deep, non-standard fk on Computers, extra context variable ## yields 'object'='company', and 'object_list'='computer_list' in context url(r'^companies/(?P\d+)/computers/$', ShowRelatedView.as_view( template_name="company/related/computers.html", model=Company, context_object_name='company', relation_chain=OrderedDict([ ('company',People.objects.all()) , ('owner',Computer.objects.all()) ]) context_list_name='computer_list', ), name='computers_for_company' ), ## Three levels deep, keep intermediary object lists, don't use alias for final 'object_list' ## yields 'object'='company', 'owner_list', 'computer_list', and 'object_list' (of Software objects) in context url(r'^companies/(?P\d+)/software_downloads/$', ShowRelatedView.as_view( template_name="company/related/software.html", model=Company, context_object_name='company', relation_chain=OrderedDict([ ('company',People.objects.all()) , ('owner',Computer.objects.all()) , ('computer',Software.objects.all()) ]) context_list_name=None, keep_intermediaries = True, ), name='software_downloads_for_company' ), )