我正在使用drf和django过滤器对我的数据进行一些过滤。对于过滤后端,我使用django_filters.rest_framework.DjangoFilterBackend
。
class ProductsViewSet(LoginRequiredMixin, ModelViewSet):
authentication_classes = (authentication.SessionAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = (django_filters.rest_framework.DjangoFilterBackend,
rest_framework.filters.SearchFilter,
rest_framework.filters.OrderingFilter,)
filter_class = ProductFilter
search_fields = ("title", "description", "company", "country", "status",)
ordering_fields = ("title", "description", "company", "country", "status",)
我的过滤器类别:
class ProductFilter(filters.FilterSet):
price_from = filters.NumberFilter(field_name="price", lookup_expr="gte",
label="Min price",
min_value=0)
price_to = filters.NumberFilter(field_name="price", lookup_expr="lte",
label="Max price",
min_value=0)
# MultipleChoiceFilters
country = filters.MultipleChoiceFilter(field_name="country", choices=COUNTRY_CHOICES)
company = filters.MultipleChoiceFilter(field_name="company", choices=COMPANY_CHOICES)
status = filters.MultipleChoiceFilter(field_name="status", choices=STATUS_CHOICES)
class Meta:
model = Product
fields = ["price_from", "price_to", "country",
"company", "status"]
@property
def qs(self):
parent = super(ProductFilter, self).qs
return parent.order_by("-timestamp")
def __init__(self, *args, **kwargs):
super(ProductFilter, self).__init__(*args, **kwargs)
user = self.request.user
user_products = Product.objects.filter(user=user)
# Initial Data #############################################################
price_min = user_products.all().aggregate(Min("price"))["price__min"]
price_max = user_products.all().aggregate(Max("price"))["price__max"]
self.filters["price_from"].extra["initial"] = price_min
self.filters["price_to"].extra["initial"] = price_max
COUNTRY_CHOICES = tuple(Product.objects.filter(user=user).values_list("country", "country__name").distinct().order_by("country__name"))
self.filters["country"].extra['choices'] = COUNTRY_CHOICES
COMPANY_CHOICES = tuple(Product.objects.filter(user=user).values_list("company", "company").distinct().order_by("company"))
self.filters["company"].extra['choices'] = COMPANY_CHOICES
我的问题是,如果我尝试使用多个值进行筛选,而其中一个值不存在,我将不会得到任何结果。
例如,如果我想根据ForeignKey的字段公司进行筛选,请使用2个值:
id=2的谷歌公司不存在于我的任何对象和中
id=3的微软公司确实存在,
以下将不返回任何结果
api/products?company=2&company=3
如果字段只是一个CharField,也会发生同样的情况。此外,在使用filter_fields和filter_class时也会出现相同的行为。
起初,我已经实现了自己的过滤自定义get_queryset
,但我认为使用过滤器后端可能会使事情变得不那么复杂。
我不知道为什么会发生这种情况,如果我过滤的两个值存在,一切都很好。
在ProductFilter
类中,您可以指定字段用于运行查询的方法。使用过滤器,您需要将company
字段的这些值组合起来进行搜索。你所做的是提供独立的价值观。你想做的是把它改成类似的事情;
api/products?company=2+3
class ProductFilter(django_filters.FilterSet):
company = django_filters.CharFilter(
label=_('Company'),
method='company_filter'
)
def company_box_filter(self, qs, name, value):
"""
Override the filter method in order to lookup for more than one field.
"""
if not value:
return qs
ids = value.split()
return qs.filter(id__in=ids)