How to display instances from two different django models on the same template, inside the same table?

Viewed 264

In a django app I've created different models and everything looks okay until I try using data from two different models inside the same table. To sum it up: in the homepage, I need to create a table that contains data from both the models, ordered by date.

The two models I need to display are the following.

models.py

class Document(models.Model):
    number = models.CharField(max_length=10)
    description = models.CharField(max_length=50)
    assigned = models.BooleanField
    validity_date = models.DateField
    is_issued = models.BooleanField

class Program(models.Model):
    name = models.CharField(max_length=25)
    description = models.CharField(max_length=100)
    validity_date = models.DateField

Then, I tried to create a view that would allow me to work with different models.

This is my view.py:

class BaseView(generic.ListView):
    template_name = 'base/base_list.html'
    context_object_name = 'base_list'

    def get_queryset(self):
         queryset = Document.objects.order_by('due_date')
         return queryset

    def get_context_data(self, **kwargs):
        context = super(BaseView, self).get_context_data(**kwargs)
        context['Programs'] = Program.objects.all()
        context['Employees'] = Employee.objects.all()
        return context

Now how can I create inside the template a table that shows both the models at once, ordering each entry by validity date (no matter if the entry belongs to Program or to Document)?

Thank you in advance!

2 Answers

You need to first query both the models, chain them together (Concatenate them) and then order by their shared attribute, that is the validity_date. You may do something like:

from itertools import chain
documents = Documents.objects.all()
programs = Program.objects.all()
final_combined_list = sorted(chain(documents,programs),key=lambda instance: instance.validity_date)

You can now simply pass final_combine_list to the template and render it to display it in the manner you want.

def get_context_data(self, **kwargs):
    context = super(BaseView, self).get_context_data(**kwargs)
    context['object_list'] = sorted(
        itertools.chain(Document.objects.all(), Program.objects.all()),
        key=lambda x: x.validity_date
    )
    return context
Related