Display data by date, when data comes from multiple models in Django

Question:

I’m currently working on an app with Django 4.1. I try to display a resume of some data comming from the database. Here is a simplified example of my models:

class Signal(models.Model):
   data1 = models.CharField()
   data2 = models.CharField()
   date = models.DateTimeField()


class Ban(models.Model):
   data3 = models.CharField()
   data4 = models.CharField()
   date = models.DateTimeField()

What I’m trying to do is getting filtered data from these 2 models, and make a list ordered by date from all this data to display it. someting like:

  • Ban1 (08/03/2023)
  • Ban2 (07/03/2023)
  • Signal2 (06/03/2023)
  • Ban3 (05/03/2023)
  • Signal1 (04/03/2023)

Thanks in advance for your ideas

Asked By: Tartempion34

||

Answers:

You can use .values() to get rid of the model layer and produce dicts containing the exact same fields.
You’ll then be able to .union() to gather your data in a single queryset.
Then a simple .order_by() should do the trick.

signals = signals.annotate(data3=Value(""), data4=Value("")).values("data1", "data2", "data3", "data4", "date")
bans = bans.annotate(data1=Value(""), data2=Value("")).values("data1", "data2", "data3", "data4", "date")
combined_queryset = qignals | bans
combined_queryset = combined_queryset.order_by("date")

If data1 and data3 should be in the same column you can do

signals = signals.annotate(new_data1=F("data1"), new_data2=F("data2")).values("new_data1", "new_data2", "date")
bans = bans.annotate(new_data1=F("data3"), new_data2=F("data4")).values("new_data1", "new_data2", "date")
combined_queryset = qignals | bans
combined_queryset = combined_queryset.order_by("date")
Answered By: Alombaros

You can use Django’s queryset API to retrieve and combine the data from the Signal and Ban models, and then sort them by date.

from django.shortcuts import render
from .models import Signal, Ban

def resume_view(request):
    signals = Signal.objects.order_by('-date')[:5]
    bans = Ban.objects.order_by('-date')[:5]

data = sorted(list(signals) + list(bans), key=lambda x: x.date, reverse=True)

context = {'data': data}
return render(request, 'resume.html', context)

In your html:

{% for item in data %}
  <p>{{ item.__class__.__name__ }}{{ forloop.counter }} ({{ item.date|date:"d/m/Y" }})</p>
{% endfor %}
Answered By: H.Selin Tüncer
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.