代码之家  ›  专栏  ›  技术社区  ›  Bulva

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

  •  0
  • Bulva  · 技术社区  · 5 年前

    我在用 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()
    

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

    例如,如果用户发送 从…开始 迄今为止 使用日期查询筛选数据。但用户也希望使用 从…开始 , 迄今为止 颜色 或其他参数的组合。有些参数可以省略。这段代码只是最低版本。我有更多的参数,我不想为每一个参数组合写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)
    
    0 回复  |  直到 5 年前
        1
  •  2
  •   Endre Both    5 年前

    将参数转换为查询过滤器不能完全自动化,因为只有您知道哪些参数应该以哪种方式过滤哪个字段。但除非你有疯狂的 or and 标准,这应该是非常简单的,因为你可以链 .filter() 不受任何限制的通话,只要你愿意 所有标准:

    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)
    

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

    如果你需要 (一些)你的标准,你需要 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)
    
        2
  •  1
  •   Braden Holt    5 年前

    这是我用于自定义筛选的模式。如果最终需要围绕每个过滤器参数进行更多自定义实现,那么可以使用策略设计模式之类的东西,这有助于摆脱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