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
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")
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 %}
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
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")
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 %}