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

如何在Django REST API中按subcategory字段过滤数据?

问题根源

你这段代码的核心问题是:虽然根据URL参数过滤出了符合条件的items,但最终返回的还是全量数据的序列化结果——因为你先对全量queryset做了序列化,后续过滤后的items完全没被用到,直接返回了初始的serializer.data。

修复后的视图代码
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .models import Item
from .serializers import ItemSerializer

@api_view(['GET'])
def view_items(request):
    # 初始化全量查询集
    queryset = Item.objects.all()

    # 处理URL参数过滤
    if request.query_params:
        # 只允许指定字段过滤,避免恶意参数注入
        allowed_filters = ['category', 'subcategory']
        filter_params = {k: v for k, v in request.query_params.dict().items() if k in allowed_filters}
        items = queryset.filter(**filter_params)
    else:
        items = queryset

    # 对过滤后的查询集做序列化
    serializer = ItemSerializer(items, many=True)

    # 判断是否有结果返回
    if items.exists():
        return Response(serializer.data)
    else:
        return Response(status=status.HTTP_404_NOT_FOUND)

@api_view(['GET'])
def ApiOverview(request):
    api_urls = {
        'all_items': '/',
        'Search by Category': '/?category=category_name',
        'Search by Subcategory': '/?subcategory=subcategory_name',
    }
    return Response(api_urls)
关键修改说明
  • 把序列化步骤移到过滤逻辑之后,确保用过滤后的items生成返回数据
  • 增加了过滤字段白名单:直接用**request.query_params.dict()存在安全风险(比如攻击者传入非法字段导致报错),只保留category和subcategory作为可过滤字段更稳妥
  • 用items.exists()替代直接判断if items:QuerySet做布尔判断时会执行全量查询,exists()只检查是否有数据,性能更优
进阶优化(可选)

如果后续需要更复杂的过滤规则(比如模糊查询、范围查询),可以用DRF官方推荐的django-filter工具:

  1. 安装依赖
pip install django-filter
  1. 在settings.py中添加配置
INSTALLED_APPS = [
    ...
    'django_filters',
    'rest_framework',
]

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
}
  1. 定义过滤规则(新建filters.py)
import django_filters
from .models import Item

class ItemFilter(django_filters.FilterSet):
    class Meta:
        model = Item
        fields = ['category', 'subcategory']
  1. 改用类视图(更符合DRF最佳实践)
from rest_framework.viewsets import ReadOnlyModelViewSet
from .models import Item
from .serializers import ItemSerializer
from .filters import ItemFilter

class ItemViewSet(ReadOnlyModelViewSet):
    queryset = Item.objects.all()
    serializer_class = ItemSerializer
    filterset_class = ItemFilter
  1. 更新URL配置
from rest_framework.routers import DefaultRouter
from .views import ItemViewSet, ApiOverview

router = DefaultRouter()
router.register(r'all', ItemViewSet)

urlpatterns = [
    path('', ApiOverview, name='home'),
] + router.urls

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 16:37:33