Django中嵌套在其他序列化器内的序列化器如何通过URL参数过滤?
问题描述
我正在开发一个包含嵌套数据的API,需要通过URL参数搜索嵌套数据,要求搜索嵌套序列化器的字段后,仅返回匹配的嵌套条目,过滤掉其他不匹配的嵌套条目。
现有代码如下:
模型定义
class Robot(models.Model): robot = models.CharField(max_length=100) short_Description = models.CharField(max_length=200) status = models.CharField(max_length=20) parameter = models.CharField(max_length=200) jenkins_job = models.CharField(max_length=100, default='JenkinsJobName') jenkins_token = models.CharField(max_length=100, default='JenkinsToken') def __str__(self): return self.robot class assignParameter(models.Model): parameterName = models.CharField(max_length=100, blank=True) assignRobot= models.ForeignKey(Robot, on_delete=models.CASCADE, related_name='param', blank=True, null=True)
序列化器代码(serializer.py)
from .models import Robot,assignParameter from rest_framework import serializers class assignParameterSerializer(serializers.ModelSerializer): class Meta: model = assignParameter fields = ['id', 'parameterName', 'assignRobot'] class RobotSerializer(serializers.ModelSerializer): param = assignParameterSerializer(many=True, read_only=True) # 注:原代码中的jenkinsHistorySerializer未提供对应模型定义,可根据实际需求保留或删除 JenkinJobName = jenkinsHistorySerializer(many=True, read_only=True) class Meta: model = Robot fields = ['id', 'robot', 'short_Description', 'status', 'parameter', 'jenkins_job', 'jenkins_token', 'param']
视图代码
class RobotViewSet(viewsets.ModelViewSet): queryset = Robot.objects.all() serializer_class = RobotSerializer filter_backends = [filters.DjangoFilterBackend] filterset_fields = ['robot', 'JenkinJobName__jenkinsBuildNumber'] authentication_classes = [BasicAuthentication] permission_classes = [IsAuthenticated]
当前问题:可以通过/?robot=robotname搜索指定的Robot实例,但嵌套字段筛选不生效,无法过滤掉不匹配的嵌套条目。
问题原因
- 默认的DjangoFilterBackend只会过滤父级模型(Robot)的查询集,筛选逻辑仅判断「该Robot是否存在符合条件的关联子数据」,不会对子数据本身进行过滤,因此返回的Robot实例依然会携带所有关联的子数据。
- 原filterset_fields配置的筛选字段和实际需要筛选的嵌套字段不匹配,如果你要筛选param下的parameterName,现有配置没有对应字段声明。
解决方案
步骤1:自定义FilterSet配置正确的筛选字段
先在视图所在文件新增FilterSet定义,指定需要的嵌套筛选字段:
from django_filters.rest_framework import FilterSet, filters from django.db.models import Prefetch from .models import Robot, assignParameter class RobotFilterSet(FilterSet): # 定义嵌套筛选参数,parameter_name为URL中传参的参数名 parameter_name = filters.CharFilter(field_name='param__parameterName', lookup_expr='exact') class Meta: model = Robot fields = ['robot', 'parameter_name']
步骤2:重写视图的get_queryset方法,预过滤关联子数据
修改RobotViewSet,在返回查询集前先对关联的param数据做筛选,同时替换原filterset_fields配置为自定义的FilterSet:
class RobotViewSet(viewsets.ModelViewSet): serializer_class = RobotSerializer filter_backends = [filters.DjangoFilterBackend] filterset_class = RobotFilterSet # 替换为自定义FilterSet authentication_classes = [BasicAuthentication] permission_classes = [IsAuthenticated] def get_queryset(self): queryset = Robot.objects.all() # 获取URL传入的parameter_name筛选参数 param_name = self.request.query_params.get('parameter_name', None) if param_name: # 对关联的param数据进行prefetch_related并过滤 queryset = queryset.filter(param__parameterName=param_name).prefetch_related( Prefetch('param', queryset=assignParameter.objects.filter(parameterName=param_name)) ).distinct() return queryset
效果验证
配置完成后访问/?parameter_name=你要搜索的参数名,返回的Robot实例只会携带符合条件的param嵌套条目,其他不匹配的条目会被过滤。
内容的提问来源于stack exchange,提问作者Rituparna Das
相关产品推荐
相关产品推荐

