You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django Rest Framework中实现非精确匹配的多对象查询?

DRF类视图实现参数不匹配的单/批量搜索优化

问题背景

需要基于Django Rest Framework(DRF)实现支持单对象查询、多对象批量搜索的类视图,但用户传入的搜索参数与数据库存储值格式不一致:比如用户习惯搜索PO-12345,但数据库仅存储12345。当前实现仅支持单个对象查询,无法处理批量搜索需求,希望找到更简便的参数映射/调整方式。

现有实现代码:

class PurchaseOrderViewSet(ReadOnlyModelViewSet):
    queryset = PurchaseOrder.objects.all()
    lookup_field = "po"

    def get_object(self):
        po_num = self.kwargs.get("pk").replace("PO-", "")
        
        self.kwargs = {"po": po_num}
        return super().get_object()

优化方案

方案1:重写get_queryset实现轻量批量搜索

如果只需要简单支持查询参数的批量搜索(比如通过?po=PO-12345,PO-67890传入多个值),直接重写get_queryset方法清洗参数即可,同时保留原单对象查询逻辑:

from django.db.models import Q
from rest_framework import viewsets

class PurchaseOrderViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = PurchaseOrder.objects.all()
    lookup_field = "po"

    def get_object(self):
        # 保留单个对象的路径参数处理逻辑
        po_num = self.kwargs.get("pk").replace("PO-", "")
        self.kwargs["po"] = po_num
        return super().get_object()

    def get_queryset(self):
        queryset = super().get_queryset()
        po_param = self.request.query_params.get("po")
        if po_param:
            # 拆分批量参数并清洗每个值的格式
            cleaned_po_list = [po.replace("PO-", "") for po in po_param.split(",")]
            # 匹配所有清洗后的采购订单号
            queryset = queryset.filter(Q(po__in=cleaned_po_list))
        return queryset

方案2:自定义过滤器类(规范复用方案)

如果项目中有多个类似的参数格式转换需求,使用DRF的FilterSet更易维护,也符合DRF的设计规范:

首先确保安装了django-filter(执行pip install django-filter),然后实现过滤器和视图:

import django_filters
from rest_framework import viewsets
from rest_framework import filters

class PurchaseOrderFilter(django_filters.FilterSet):
    # 自定义处理po参数的过滤器
    po = django_filters.CharFilter(method="clean_po_and_filter")

    def clean_po_and_filter(self, queryset, name, value):
        # 处理单个或批量传入的po参数,统一清洗格式
        cleaned_pos = [item.replace("PO-", "") for item in value.split(",")]
        return queryset.filter(po__in=cleaned_pos)

    class Meta:
        model = PurchaseOrder
        fields = ["po"]

class PurchaseOrderViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = PurchaseOrder.objects.all()
    lookup_field = "po"
    # 启用DjangoFilterBackend并绑定自定义过滤器
    filter_backends = [filters.DjangoFilterBackend]
    filterset_class = PurchaseOrderFilter

    def get_object(self):
        po_num = self.kwargs.get("pk").replace("PO-", "")
        self.kwargs["po"] = po_num
        return super().get_object()

方案说明

  • 方案1轻量直接,适合简单场景,不需要额外依赖;
  • 方案2更规范,过滤器逻辑可以单独复用,适合复杂或多场景的参数处理需求;
  • 两种方案都同时支持路径参数的单对象查询(比如/purchase-orders/PO-12345/)和查询参数的批量搜索(比如/purchase-orders/?po=PO-12345,PO-67890),完全覆盖需求。

内容的提问来源于stack exchange,提问作者User

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 07:05:57