Как использовать мультитеговые фильтры в ответе API Django REST Framework?
Прежде всего, я извиняюсь, если я не задал вопрос, используя лучшие слова. Я создаю приложение DRF, у меня есть Products
Модель, ProductSerializer
и ProductsSummaryView
. Кроме того, у меня есть Workspace Model (не буду говорить об этом, так как это не относится к вопросу). Теперь я хочу возвращать в ответе success те данные о товарах, которые привязаны к определенному рабочему пространству, отфильтрованные по некоторым параметрам
Что я сделал:
Я определил filterset_fields
и filter_backends
. Все работает нормально. Например, если я перейду по этому URL {{domain}}/path/?country__title=Japan
, он отфильтрует данные по Японии и покажет их мне. Но проблема в том, что я хочу фильтровать, используя мульти-тег, например, если я хочу увидеть детали для Японии и Кореи, то я хочу что-то вроде этого {{domain}}/path/?country__title=Japan&country__title=Korea
, но это не работает, и он просто возвращает все детали. Я даже попробовал добавить формат пустого списка в URL и попробовал этот URL {{domain}}/path/?country__title[]=Japan&country__title[]=Korea
, но он все равно не работает.
Может ли кто-нибудь помочь мне в этом?
Моя Product
модель:
class Product(BaseModel):
"""Product model to store all prices of a product and
related brand and countries it's available in"""
product = models.CharField(max_length=255)
country = models.ForeignKey(Country, null=True, on_delete=models.DO_NOTHING)
car_brand = models.ForeignKey(
CarBrand, on_delete=models.DO_NOTHING, null=True, blank=True
)
part = models.ForeignKey(Part, null=True, blank=True, on_delete=models.DO_NOTHING)
fzg_segment = models.ForeignKey(
FZGSegment, on_delete=models.DO_NOTHING, null=True, blank=True
)
parts_group = models.ForeignKey(
PartsGroup, on_delete=models.DO_NOTHING, null=True, blank=True
)
last_collected = models.DateField(null=True, blank=True)
usage_recommendation = models.CharField(max_length=255)
recommended_action = models.CharField(max_length=255)
recommended_action_value = models.DecimalField(max_digits=6, decimal_places=2)
recommended_price = models.DecimalField(max_digits=6, decimal_places=2)
rrp = models.DecimalField(max_digits=6, decimal_places=2)
iam_price = models.DecimalField(max_digits=6, decimal_places=2)
currency = models.ForeignKey(
Currency, null=True, blank=True, on_delete=models.DO_NOTHING
)
iam_index = models.DecimalField(max_digits=6, decimal_places=2)
factor = models.DecimalField(max_digits=6, decimal_places=2)
items_count = models.PositiveIntegerField(default=0)
manufacturer = models.ForeignKey(
Manufacturer, on_delete=models.DO_NOTHING, null=True, blank=True
)
is_in_stock = models.BooleanField(default=True)
added_at = models.DateField(null=True, blank=True)
last_in_stock = models.DateField(null=True, blank=True)
last_searched_at = models.DateField(null=True, blank=True)
avg_in_stock = models.DecimalField(
null=True, blank=True, max_digits=6, decimal_places=2
)
def __str__(self):
return self.product
Мой ProductSerializer
сериализатор:
class ProductSerializer(serializers.ModelSerializer):
"""Serializer for the part object"""
parts_group = PartsGroupSerializer()
fzg_segment = FZGSegmentSerializer()
class Meta:
model = Product
fields = (
"id",
"product",
"fzg_segment",
"parts_group",
"last_collected",
"usage_recommendation",
"recommended_action",
"recommended_action_value",
"recommended_price",
"rrp",
"iam_price",
"iam_index",
"factor",
"items_count",
)
read_only_fields = ("id",)
А мой ProductsSummaryView
API:
class ProductsSummaryView(mixins.ListModelMixin, viewsets.GenericViewSet):
"""Viewset to return data for products in a workspace"""
serializer_class = serializers.ProductSerializer
permission_classes = (permissions.IsWorkspaceAdminPermission,)
pagination_class = StandardSetPagination
filter_backends = [DjangoFilterBackend]
filterset_fields = [
"fzg_segment__title",
"parts_group__title",
"car_brand__title",
"usage_recommendation",
"recommended_action",
]
def get_queryset(self) -> models.Product:
"""Returns queryset of all the products of a workspace"""
workspace = self.kwargs["workspace"]
workspace = get_object_or_404(models.Workspace, pk=workspace)
return workspace.products.all()
Может ли кто-нибудь помочь мне и сообщить, что мне нужно сделать, чтобы достичь желаемой функциональности?
Для фильтрации набора запросов на основе нескольких значений определенного поля в Django Rest Framework (DRF) вы можете использовать тип поиска in в вашем наборе фильтров. Чтобы использовать этот тип поиска, вам нужно обновить поля вашего набора фильтров, включив в них тип поиска in следующим образом:
class ProductFilter(filters.FilterSet):
country__title = filters.CharFilter(field_name='country__title', lookup_expr='in')
class Meta:
model = Product
fields = ['country__title']
После этого набора фильтров вы можете использовать тип поиска в параметрах запроса URL для фильтрации набора запросов на основе нескольких значений. Например, чтобы отфильтровать набор запросов для продуктов со странами "Япония" и "Корея", вы можете использовать следующий URL:
{{domain}}/path/?country__title__in=Japan,Korea
Альтернативно, вы также можете использовать MultipleChoiceFilter, предоставляемый Django-filter в вашем наборе фильтров, чтобы позволить фильтрацию по нескольким значениям для определенного поля.
class ProductFilter(filters.FilterSet):
country__title = filters.MultipleChoiceFilter(field_name='country__title')
class Meta:
model = Product
fields = ['country__title']
С помощью этого набора фильтров вы можете использовать следующий URL для фильтрации набора запросов для продуктов со странами "Япония" и "Корея":
{{domain}}/path/?country__title=Japan&country__title=Korea
Вам необходимо использовать BaseInFilter, пример:
from django_filters.filters import BaseInFilter
from django_filters import rest_framework as filters
class CharInFilter(BaseInFilter, filters.CharFilter):
pass
class ProductFilterSet(filters.FilterSet):
country = CharInFilter(field_name="country__title", lookup_expr='in')
class Meta:
model = Product
fields = ["country"]
Урл параметров выглядит следующим образом:
/?country=Japan,Korea