0

I have this model:

class Auction(models.Model):
    start_price = models.IntegerField()
    price_step = models.IntegerField()
    finish_time = models.DateTimeField()

    @property
    def is_active(self):
        return self.finish_time > timezone.now()

I also have this in my serializer class:

class AuctionSerializer(serializers.ModelSerializer):
    is_active = serializers.ReadOnlyField()

    class Meta:
        model = Auction
        fields = '__all__'

And this in my view class:

class AuctionViewSet(ModelViewSet):
    queryset = Auction.objects.all()
    serializer_class = AuctionSerializer
    filter_backends = (DjangoFilterBackend,)
    filter_fields = ('is_active',)

But it throws "'Meta.fields' contains fields that are not defined on this FilterSet: is_active". I can use it as a serializer field but I can't do filtering by this field. How do I properly implement filtering by model property not just model field?

Dmitry Sazhnev
  • 383
  • 3
  • 16
  • Possible duplicate of [ModelSerializer using model property](https://stackoverflow.com/questions/17066074/modelserializer-using-model-property) – RishiG Apr 28 '18 at 16:10
  • This is different. I've already put is_active in serializer, I need the view to be filtered by this field. – Dmitry Sazhnev Apr 29 '18 at 08:39

1 Answers1

1

AFAIK, django-filter does not support filtering by properties.

One way to do this would be to expose the model as-is; and expect the FE to filter accordingly.

For example: the filter URI could look like http://localhost:8000/api/auctions/?finish_time__gte=2018-04-28T00:00:00

If however, you want an explicit declaration; you can override the get_queryset method in ModelViewSet as follows:

class AuctionViewSet(ModelViewSet):
    queryset = Auction.objects.all()
    serializer_class = AuctionSerializer
    filter_backends = (DjangoFilterBackend,)
    filter_fields = ('is_active',)

    def filter_active(qs):
        return qs.filter(finish_time__gte=timezone.now())

    def filter_inactive(qs):
        return qs.filter(finish_time__lt=timezone.now())

    def get_queryset():
        qs = super(AuctionViewSet, self).get_queryset()
        is_active = self.request.GET.get('is_active', None)  # This will be a string
        if is_active is None:
            pass
        elif is_active == 'true':
            qs = self.filter_active(qs)
        elif is_active == 'false':
            qs = self.filter_inactive(qs)
        else:
            pass  # Some other value
        return qs

Reference: https://django-filter.readthedocs.io/en/master/guide/rest_framework.html#schema-generation-with-core-api

rtindru
  • 5,107
  • 9
  • 41
  • 59