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))