Django Rest Framework filtering calculated model property Django Rest Framework filtering calculated model property django django

Django Rest Framework filtering calculated model property


You can create custom filter for slipdate, netweight that will evaluate and filter this fields in db. For this you can use conditional expressions and F expression

from django.db.models import F, Case, Whenclass WeightSlipFilter(FilterSet):    slipdate = DateTimeFilter(method='filter_slipdate')    netweight = NumberFilter(method='filter_netweight')    class Meta:        model = WeightSlip        fields = ('slipdate', 'netweight', 'vehicle')    def filter_netweight(self, queryset, value):        if value:            queryset = queryset.annotate(netweight=F('grossweight') - F('tareweight')).filter(netweight=value)        return queryset    def filter_slipdate(self, queryset, value):        if value:            queryset = queryset.annotate(slipdate=Case(When(grossdate__gt=F('taredate'), then=F('grossdate')), default=F('taredate')).filter(slipdate=value)        return queryset


Note that if you're using the latest version of django-filter, Filter.method takes 4 arguments, like so:

def filter_slipdate(self, queryset, name, value):    if value:        queryset = queryset.annotate(slipdate=Case(When(grossdate__gt=F('taredate'), then=F('grossdate')), default=F('taredate')).filter(slipdate=value)    return queryset

```


Extending the answer further. With the latest django and drf version one might experience an exception like this.

Exception

File "/home/USER/.env/drf3/lib64/python3.7/site-packages/django/db/models/query.py", line 76, in itersetattr(obj, attr_name, row[col_pos])AttributeError: can't set attribute

Versions Used: Django==3.1 djangorestframework==3.11.1 django-filter==2.3.0

The solution that worked for me is this where slipdate and netweight requires model name to be used in the queryset...

def filter_slipdate(self, queryset, name, value):    if value:       queryset = queryset.annotate(WeightSlip__slipdate=Case(When(grossdate__gt=F('taredate'), then=F('grossdate')), default=F('taredate'))).filter(WeightSlip__slipdate=value)    return querysetdef filter_netweight(self, queryset, name, value):    if value:        queryset = queryset.annotate(WeightSlip__netweight=F('grossweight') - F('tareweight')).filter(WeightSlip__netweight=value)    return queryset    return queryset