API端点中的多个过滤器参数-DRF

时间:2019-03-10 17:17:56

标签: django django-rest-framework django-filter

我正在将Django rest framework用于我的REST API。我有端点,其中有一些要过滤的参数,如下所示:

# in my view
from_date = self.request.query_params.get('from', None)
to_date = self.request.query_params.get('to', None)
category = self.request.query_params.get('category', None)
color = self.request.query_params.get('color', None)

然后在选择数据的地方有if / else代码。第一次只有两个参数,所以还可以,但是后来我添加了更多的参数进行过滤,现在我认为这段代码看起来不太好,我认为需要进行一些优化。而且,不同参数的组合现在不起作用。

实际代码(在我看来):

if from_date is not None and to_date is not None:
    something = Something.objects.filter(send_date__range=(from_date, to_date))
elif category:
    something = Something.objects.filter(values__something__category__name__iexact=category)
elif color:
    something = Something.objects.filter(values__something__color__name__iexact=color)
else:
    something = Something.objects.all()

DRF中是否有内置的选项或Django中的某种类型的组合过滤,考虑到值可以为None,如何将参数组合到一个大查询中?

例如,如果用户使用日期发送起始日期起始日期查询过滤器数据。但是用户还希望使用 from_date to_date 颜色或其他参数组合来过滤数据。一些参数可以省略。该代码仅是最低版本。我有更多参数,我不想为每种参数组合都写if和else。

类似于的东西(但如果其中一个值是None,则不使用该值将无法工作)

Something.objects.filter(send_date__range=(from_date, to_date))
    .filter(values__something__category__name__iexact=category)
    .filter(values__something__color__name__iexact=color)

2 个答案:

答案 0 :(得分:1)

将参数转换为查询过滤器不能完全自动化,因为只有您知道应该以哪种方式在哪些字段上过滤哪些参数。但是除非您有orand准则的疯狂组合,否则它应该非常简单,因为您可以无限制地链接.filter()个呼叫,只要您想and全部条件:

something = Something.objects.all()
if from_date and to_date:
    something = something.filter(send_date__range=(from_date, to_date))
if category:
    something = something.filter(values__something__category__name__iexact=category)
if color:
    something = something.filter(values__something__color__name__iexact=color)

这涵盖了所有组合并且看起来很容易管理,不是吗?

如果您需要or(某些)条件,则需要Q objects,但是可以用相同的方式进行链接:

from django.db.models.query_utils import Q

qq = Q()
if category:
    qq = qq | Q(values__something__category__name__iexact=category)
if color:
    qq = qq | Q(values__something__color__name__iexact=color)
something = Something.objects.filter(qq)

答案 1 :(得分:1)

这是我用于自定义过滤的模式。如果最终需要围绕每个过滤器参数进行更多的自定义实现,则可以使用诸如策略设计模式之类的东西,它可以消除if-else链。

FILTER_PARAMS = {'from': 'from_date', 'to': 'to_date', 'category': 'values__something__category__name__iexact', 'color': 'values__something__color__name__iexact'}

def get(self):
        filter_params = self.get_filter_params(self.request.query_params)
        qs = queryset.filter(**filter_params)

def get_filter_params(self, query_params):
        fields = {}

        for k, v in query_params.items():
                if k in self.FILTER_PARAMS:
                    fields[self.FILTER_PARAMS[k]] = v
        return fields