小能豆

django filters icontains with __in lookup

py

I am attempting to filter a single field with multiple values using the django-filters package. For example, I have a model Content with field paragraph. I want to return the object if Content.paragraph contains string “McDonald” or Content.paragraph contains string “MacDonald”. Essentially be able to pass multiple icontains to a single field. I would like to be able to pass theoretically infinite values, not just two. Thanks!


阅读 69

收藏
2023-11-29

共1个答案

小能豆

In Django, if you want to filter a model based on multiple values for a single field, you can use the Q object from the django.db.models module. You can create a dynamic Q object by iterating through your list of values and combining them with the | (OR) operator. Then, you can use this Q object in your queryset.

Here’s an example using the icontains filter for the paragraph field:

from django.db.models import Q
from django_filters import rest_framework as filters
from .models import Content

class ContentFilter(filters.FilterSet):
    paragraph_contains = filters.CharFilter(method='filter_paragraph_contains')

    class Meta:
        model = Content
        fields = ['paragraph_contains']

    def filter_paragraph_contains(self, queryset, name, value):
        # Split the input value into a list of search terms
        search_terms = value.split()

        # Create a dynamic Q object combining icontains for each search term
        q_objects = Q()
        for term in search_terms:
            q_objects |= Q(paragraph__icontains=term)

        # Apply the filter to the queryset
        queryset = queryset.filter(q_objects)

        return queryset

In this example:

  • We define a custom filter named paragraph_contains.
  • We use the CharFilter to accept a string value.
  • In the filter_paragraph_contains method, we split the input value into a list of search terms.
  • We then create a dynamic Q object by iterating through the search terms and combining them with the | operator.
  • Finally, we apply the filter to the queryset using filter(q_objects).

Now, when you use this filter in your Django view or DRF endpoint, you can pass a string with multiple search terms separated by spaces, and it will filter the queryset accordingly.

class ContentView(generics.ListAPIView):
    queryset = Content.objects.all()
    serializer_class = ContentSerializer
    filterset_class = ContentFilter

For example:

  • /api/content/?paragraph_contains=McDonald
  • /api/content/?paragraph_contains=McDonald MacDonald
  • /api/content/?paragraph_contains=McDonald%20MacDonald (using URL-encoded spaces)
2023-11-29