Django DRF按种族筛选职位时,中间表关联数据未正确过滤
问题原因
你只是在get_queryset中过滤了Job对象,但DRF序列化时会默认取出该Job关联的所有JobRace记录,并没有对关联的中间表数据做筛选,所以返回的job_race字段包含了该职位所有种族的关联数据。
解决方法
方法1:在序列化器中动态过滤关联字段
修改你的JobSerializer,在序列化job_race字段时,根据请求参数过滤对应的JobRace记录:
from rest_framework import serializers from .models import Job, JobRace class JobRaceSerializer(serializers.ModelSerializer): class Meta: model = JobRace fields = ['id', 'race', 'image'] class JobSerializer(serializers.ModelSerializer): job_race = serializers.SerializerMethodField() def get_job_race(self, obj): # 从请求中获取race参数 race_id = self.context['request'].query_params.get('race') queryset = obj.jobrace_set.all() if race_id: queryset = queryset.filter(race_id=race_id) return JobRaceSerializer(queryset, many=True).data class Meta: model = Job fields = ['id', 'title', 'job_race']
当请求带有race参数时,job_race字段只会返回对应种族的关联记录;无参数时返回所有关联记录。
方法2:在查询时预筛选关联数据(使用Prefetch)
在get_queryset中使用Prefetch对象,预加载并过滤JobRace数据,既避免N+1查询,又只获取符合条件的关联记录:
from django.db.models import Prefetch from rest_framework import viewsets from .models import Job, JobRace from .serializers import JobSerializer class JobViewSet(viewsets.ModelViewSet): serializer_class = JobSerializer queryset = Job.objects.all() def get_queryset(self): queryset = super().get_queryset() race_id = self.request.query_params.get('race') if race_id: # 预加载并过滤JobRace prefetch = Prefetch( 'jobrace_set', queryset=JobRace.objects.filter(race_id=race_id), to_attr='filtered_job_race' ) queryset = queryset.filter(jobrace__race_id=race_id).prefetch_related(prefetch).distinct() return queryset
然后修改序列化器,使用预加载的filtered_job_race属性:
class JobSerializer(serializers.ModelSerializer): job_race = serializers.SerializerMethodField() def get_job_race(self, obj): # 优先使用预筛选的关联数据,没有则用全部 queryset = getattr(obj, 'filtered_job_race', obj.jobrace_set.all()) return JobRaceSerializer(queryset, many=True).data class Meta: model = Job fields = ['id', 'title', 'job_race']
注意事项
- 如果你的模型中
Job和JobRace的反向关联名称不是jobrace_set,要替换成实际名称(比如你在JobRace的job字段设置了related_name,就用该名称)。 - 使用
distinct()是为了避免多对多关联导致的Job对象重复。
内容的提问来源于stack exchange,提问作者Anibal Cardozo
相关产品推荐
相关产品推荐

