Sorry for a newbie question. I have a following model:
class WeightSlip(models.Model):
grossdate = models.DateTimeField(auto_now=False, auto_now_add=False)
grossweight = models.DecimalField(max_digits=6, decimal_places=2, default=0)
taredate = models.DateTimeField(auto_now=False, auto_now_add=False)
tareweight = models.DecimalField(max_digits=6, decimal_places=2, default=0)
vehicle = models.CharField(max_length=12)
@property
def netweight(self):
return self.grossweight - self.tareweight
@property
def slipdate(self):
if self.grossdate > self.taredate:
return grossdate.date()
else:
return taredate.date()
Serializer:
class WeightSlipSerializer(serializers.ModelSerializer):
class Meta:
model = models.WeightSlip
fields = ('grossdate', 'grossweight', 'taredate', 'tareweight', 'slipdate', 'netweight', 'vehicle')
read_only_fields = ('slipdate', 'netweight')
I am trying to use the django-rest-framework-filters to filter on the calculated 'netweight' and 'slipdate' properties:
class WeightSlipFilter(FilterSet):
class Meta:
model = WeightSlip
fields = ('slipdate', 'netweight', 'vehicle')
This gives me an error:
TypeError: 'Meta.fields' contains fields that are not defined on this FilterSet: slipdate, netweight
Is there a workaround to this problem other than adding the calculated fields to the database ?
Thanks in advance.
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, When
class 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