### 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<pk>\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<pk>\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<pk>\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'
),
)
Comments