[Fixed]-Django Class Based View Composite


Kenzic was able to accomplish this by doing the following:


from django.views.generic.base import TemplateResponseMixin, View

class BaseCompositeView(TemplateResponseMixin, View):

    composite_views = []

    def get_composite_views(self):
        return self.composite_views

    def get_context_data(self, request, *args, **kwargs):
        context = {}
        composite_views = self.get_composite_views()
        for composite_view in composite_views:
            cls = composite_view[0]
                clsview = cls.as_view(**composite_view[1])
            except IndexError:
                clsview = cls.as_view()

            view = clsview(request, *args, **kwargs)
            context_data = view.context_data

        return context

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(request, *args, **kwargs)
        return self.render_to_response(context)


from django.views.generic import TemplateView, ListView, DetailView
from composite import BaseCompositeView
from .models import *

class MediaCoverageList(ListView):
    queryset = MediaCoverageItem.objects.order_by('-date')

class PressKitList(ListView):
    queryset = PressKit.objects.all()

class NewsroomLanding(BaseCompositeView):
    template_name = 'newsroom/landing.html'
    composite_views = [
            'paginate_by': 10,



May be you can override the get_context_data method to add additional data to the context?

 def get_context_data(self, **kwargs):

        context = super(AuthorListView, self).get_context_data(**kwargs)
        # Add in a QuerySet of all the books
        context['press_list'] = Press.objects.all()
        context['articles_list] = Article.objects.all()
        return context

and in your template you can get the press list and the article list using {{ press_list }} and {{ articles_list }}.



In my mind, a view is simply one page. A view can have several forms, which I think is a better solution in your example.

Just split the template into several files, where each form have a small template, and use the template include directive to stitch it together. This also has the added advantage that the form can be reused in other views very simple.

Your solution is basically like frames but on the server instead of in the browser.


The simple way:

Don’t use a generic view and the paginator object manually on both queryset.

It won’t be that long, and it’s not some lines that are going to kill your DRY IMO.

The generic but long way:

Create a view that wrap the __init__ and get_context methods to pass argument to two ListView instances.

init should instanciate both ListView, pass the parameters and add the instances to attributes of the wrapper.

get_context should call the both get_context Listview instances method, and merge them into one context object.

Be sure to setup a different template_object_name for each ListView so they don’t override each other in the context dict.

Do that in a generic way, and don’t forget to pusblish you code on djangosnippet 🙂

Leave a comment