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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:55:01