I'm using Django-Filter package which is working well for the one example they have in their documentation. However, I am not trying to generate a list of objects rather filter the calculations I have done on the object fields.
Example template: https://django-filter.readthedocs.io/en/stable/guide/usage.html#the-template
{% for obj in filter.qs %}
{{ obj.name }} - ${{ obj.price }}<br />
{% endfor %}
The problem here is that a list is created.. I'm looking for my trade "stats" to be updated based on the new filter selections.
I believe I need to set up my views differently and possibly call the template objects in another way as well but not totally sure.
filters.py
class StatsFilter(django_filters.FilterSet):
class Meta:
model = Trade
fields = ['type', 'asset', 'symbol', 'broker', 'patterns', 'associated_portfolios']
views.py
class StatsView(LoginRequiredMixin, FilterView):
model = Trade
template_name = 'dashboard/stats.html'
filterset_class = StatsFilter
def get_form(self, *args, **kwargs):
form = StatsFilter()
user = self.request.user
form.fields['associated_portfolios'].queryset = Portfolio.objects.filter(user=user)
return form
def get_context_data(self, *args, **kwargs):
trade = Trade.objects.filter(user=self.request.user, status='cl').order_by('created')
all_trades = Trade.objects.filter(user=self.request.user, status='cl').count()
context = super(StatsView, self).get_context_data(*args, **kwargs)
data = [t.profit_loss_value_fees for t in trade]
context['all_trades'] = all_trades
context['gross_profit'] = sum([t.profit_loss_value for t in trade])
context['net_profit'] = sum([t.profit_loss_value_fees for t in trade])
...
return context
stats.html
<form method="get" class="row">
{{ filter.form.as_p }}
{{ form.media }}
<div class="col-xl-12">
<button class="btn btn-success float-right" type="submit">Apply</button>
</div>
</form>
<table class="table table-striped">
<tr>
<th scope="row">Net Profit <small>(Fees Included)</small></th>
<td>
{% if net_profit >= 0 %}
<font color="green">{{ net_profit|floatformat:2 }}</font>
{% else %}
<font color="red">{{ net_profit|floatformat:2 }}</font>
{% endif %}
</td>
</tr>
<tr>
<th scope="row">Gross Profit</th>
<td>{{ gross_profit|floatformat:2 }}</td>
</tr>
The secret sauce that took me weeks to find out is so obvious. Run the calcs over the filter. Example below. Also you do not need to use aggregate. Works just as well with the original way I wrote above.
context['gross_profit'] = sum([t.profit_loss_value for t in trade])
This is the key part:
trades = filter.qs.filter(status='cl')
view.py
def get_context_data(self, *args, **kwargs):
filter = StatsFilter(self.request.GET, queryset=self.get_queryset(), request=self.request)
trades_count = filter.qs.filter(status='cl').count()
trades = filter.qs.filter(status='cl')
...
context['gross_profit'] = trades.aggregate(value=Sum('profit_loss_value'))['value']