Home > Mobile >  Filter field of manytomany field by a list
Filter field of manytomany field by a list

Time:05-20

I would like to do the following with Django REST Framework:

Filter results based on a field of a manytomany field.

The query would look like this: https://endpoint.com/api/artwork/?having_style=Modern,Contemporary

I would expect the result to contain all ArtWork objects which contain a relation to a Style object with name "Modern", "Contemporary" or both.

The code below is not working and I don't know why.

models.py

class Style(models.Model):
    name = models.CharField(validators=[validate_style], max_length=100, unique=True)

class ArtWork(models.Model):
    styles = models.ManyToManyField(Style, default=None)

filters.py

class ArtWorkFilter(filters_rest.FilterSet):
    having_style = django_filters.Filter(field_name="styles__name", lookup_expr='in')

    class Meta:
        model = ArtWork
        fields = ['having_style']
class StyleSerializer(serializers.ModelSerializer):
    
    class Meta:
        model = Style
        fields = ('name',)

class ArtWorkSerializer(serializers.ModelSerializer):

    styles = StyleSerializer(many=True)

    class Meta:
        model = ArtWork
        fields = ('styles'/)

views.py

class ArtWorkViewSet(viewsets.ModelViewSet):

    permission_classes = []

    queryset = ArtWork.objects.all()
    serializer_class = ArtWorkSerializer
    filter_backends = [filters_rest.DjangoFilterBackend,]
    filterset_class= ArtWorkFilter
    pagination_class = CursorSetPagination

Thank you in advance!

Solution

I solved it by changing the ArtWorkFilter to

filters.py

class ArtWorkFilter(filters_rest.FilterSet):
    having_style = django_filters.Filter(field_name="styles__name", lookup_expr='in')

    class Meta:
        model = ArtWork
        fields = ['having_style']

    def filter_by_style_name(self, queryset, name, value):
        list_styles = value.split(',')
        return queryset.filter(styles__name__in=list_styles)

CodePudding user response:

Try adding method param in Filter declaration. Something like:

class ArtWorkFilter(filters_rest.FilterSet):
    having_style = django_filters.Filter(field_name="styles__name", method="filter_by_style_name")

    class Meta:
        model = ArtWork

    def filter_by_style_name(self, queryset, name, value):
        query_params = ... <--- make correct query here
        return queryset.filter(**{query_params})
        

CodePudding user response:

CartItem.objects.filter(cart=cart, product=product, attribute__in=attribute_list).annotate(num_attr=Count('attribute')).filter(num_attr=len(attribute_list))

  • Related