15

I would like to filter against query params in my REST API - see django docs on this. However, one parameter I wish to filter by is only available via a model @property

example models.py:

class Listing(models.Model):
    product = models.OneToOneField(Product, related_name='listing')
    ...
    @property
    def category(self):
        return self.product.assets[0].category.name

Here is the setup for my Listing API in accordance with django-filter docs

    class ListingFilter(django_filters.FilterSet):
        product = django_filters.CharFilter(name='product__name')
        category = django_filters.CharFilter(name='category') #DOES NOT WORK!!

        class Meta:
            model = Listing
            fields = ['product','category']

    class ListingList(generics.ListCreateAPIView):
        queryset = Listing.objects.all()
        serializer_class = ListingSerializer
        filter_class = ListingFilter

How can I appropriately filter by listing.category? It is not available on the listing model directly.

1

2 Answers 2

23

Use the 'action' parameter to specify a custom method - see django-filter docs

First define a method that filters a queryset using the value of the category parameter:

    def filter_category(queryset, value):
        if not value:
            return queryset

        queryset = ...custom filtering on queryset using 'value'...
        return queryset

Listing filter should look like this:

    class ListingFilter(django_filters.FilterSet):
        ...
        category = django_filters.CharFilter(action=filter_category)
        ...
Sign up to request clarification or add additional context in comments.

2 Comments

Just a quick note that the django-filter action has been replaced by method. django-filter.readthedocs.io/en/latest/migration.html
-2

For sake of database speed, you should just add the category to your listing model

class Listing(models.Model):
    product = models.OneToOneField(Product, related_name='listing')
    category = models.ForeignKey(Category)

Then use a post_save signal to keep the field updated

from django.dispatch import receiver
from django.db.models.signals import post_save

@receiver(post_save, sender=Product)
def updateCategory(sender, instance, created, update_fields, **kwargs):
    product = instance
    product.listing.category = product.assets[0].category.name
    product.listing.save()

Then filter by it's name as you would any other field:

class ListingFilter(django_filters.FilterSet):
    ...
    category = django_filters.CharFilter(name='category__name')
    ...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.