djangodjango-templatesaggregatedjango-filterconsolidation

Django Filter Consolidate data using Aggregate


I want to populate dynamic data using Django Filter Date Range, I have achieved this. In this there is a consolidated data which I am collecting of a single column, which is also working using aggregate. Now I want the consolidated to change as per the records which gets selected when date range is applied in Django filter form.

I am able to consolidate data in the column and get a total out of it in “manual_total” [when I pre-define the date field]. But when I filter using the Django Filter Date range field using Form and filters, I am not getting total as per the columns being fetched. How do I achieve it?

When I filter as per date in the form, the total should be as per the records showing post filter. For example, I have 2 records from March 1st to March 31st and 1 record for April 1st. If I filter March 1st to 31st, it shows only total of 2 records, but total it shows including the 3rd record. Below are my code and pls guide me to join the queryset and aggregate together to retrieve data as per the date range filter I select.

models.py

class Event(models.Model):
    name = models.CharField(max_length=255, null=True)
    event_date = models.DateField(default=None, null=True)
    event_price = models.IntegerField(null=True)

    def __str__(self):
        return self.name

views.py

from django.db.models import Sum

def viewEvent(request):
    event = Event.objects.all()
    manual_total = Event.objects.filter(event_date__range=["2024-03-01", "2024-03-30"]).aggregate(TOTAL=Sum('event_price'))['TOTAL']
    eventFilter = EventFilter(request.GET, queryset=event)
    event = eventFilter.qs
    total = Event.objects.aggregate(TOTAL=Sum('event_price'))['TOTAL']
    context = {'event': event, 'manual_total: manual_total', 'eventFilter': eventFilter}
    return render(request, 'view_event.html', context)

forms.py

class EventForm(forms.ModelForm):
    class Meta:
        model = Event
        fields = '__all__'
        widgets = {
            'event_date': DateInput(),

filters.py

class EventFilter(django_filters.FilterSet):
    start_date = DateFilter(field_name="event_date", lookup_expr='gte', widget=DateInput(attrs={'type': 'date'}))
    end_date = DateFilter(field_name="event_date", lookup_expr='lte', widget=DateInput(attrs={'type': 'date'}))
    total = Event.objects.aggregate(TOTAL=Sum('event_price'))['TOTAL']

    class Meta:
        model = Event
        fields = 'event_date', 'event_price'

view_event.html

{% extends 'base.html' %}
{% load static %}
{% block content %}

<br>

<div style="width:1400px; margin:0 auto;" class="row">
    <div class="col-md-8">
        <div class="card card-body">
            <h5>&nbsp; Event Report :</h5>
            <div class="row">
    <div class="col">
        <div class="card card-body">
            <form method="get">
                Event Date (Start): {{ eventFilter.form.start_date }}
                Event Date (End):{{ eventFilter.form.end_date }}

                <button class="btn btn-primary" type="submit">Filter</button>
            </form>
        </div>
    </div>
</div>
           <div class="card card-body">
      <table class="table table-sm">
        <tr>
          <th>Event Name</th>
          <th>Event Date</th>
          <th>Event Price</th>
        </tr>
        {% for items in event %}
        <tr>
          <td>{{ items.name }}</td>
          <td>{{ items.event_date }}</td>
            <td>{{ items.event_price }}</td>
          {% endfor %}
        </tr>
      </table>
              <table class="table table-sm">
        <tr>
          <th></th>
            <th></th>
            <th></th>
            <th></th>
          <th>TOTAL: {{ total }}</th>

        </tr>
              </table>
    </div>

        </div>

    </div>

</div>


{% endblock %}

Django Aggregate in Filter queryset


Solution

  • You don't use the filtered queryset, but the entire queryset. You can work with:

    class EventFilter(django_filters.FilterSet):
        start_date = DateFilter(
            field_name='event_date',
            lookup_expr='gte',
            widget=DateInput(attrs={'type': 'date'}),
        )
        end_date = DateFilter(
            field_name='event_date',
            lookup_expr='lte',
            widget=DateInput(attrs={'type': 'date'}),
        )
    
        @property
        def total(self):
            return self.qs.aggregate(TOTAL=Sum('event_price'))['TOTAL']
    
        class Meta:
            model = Event
            fields = 'event_date', 'event_price'

    and then render with:

     <th>TOTAL: {{ eventFilter.total }}</th>