如何在Django REST Framework中带过滤条件查询外键值
Hey there! I see you're trying to filter the related Score objects when using StringRelatedField in Django REST Framework, and there's also a small syntax issue in your queryset code. Let's break this down and fix it step by step.
First, let's address the immediate syntax error in your view:
Your current
User.objects.filter(score>=10)is invalid. To filter users who have at least one score >=10, you need to use Django's double-underscore notation for related fields:User.objects.filter(score__score__gte=10). But this only filters which users are returned, not which scores are included for each user.
To actually filter the scores that get serialized for each user (i.e., only return scores >=10 for a given user), StringRelatedField doesn't support filtering out of the box. Here are two solid solutions:
Solution 1: Use SerializerMethodField (Simple & Direct)
Replace StringRelatedField with SerializerMethodField so you can explicitly filter the related scores in the serializer itself. This gives you full control over which scores are included.
Update your serializer.py:
from rest_framework import serializers from .models import User, Score class UserDetailsSerializer(serializers.ModelSerializer): score = serializers.SerializerMethodField() class Meta: model = User fields = ('id', 'score', ) def get_score(self, obj): # Filter scores where value is >=10, then return their string representation filtered_scores = obj.score.filter(score__gte=10) return [str(score) for score in filtered_scores]
Solution 2: Use Prefetch (Performance-Optimized)
If you're dealing with large datasets, using Prefetch will optimize your queries by avoiding the "N+1" problem. We'll prefetch only the filtered scores upfront, then let StringRelatedField use that prefiltered data.
Update your views.py:
from django.db.models import Prefetch from rest_framework import viewsets from .models import User, Score from .serializer import UserDetailsSerializer class UserDetailsRetrieveViewSet(viewsets.ModelViewSet): serializer_class = UserDetailsSerializer def get_queryset(self): # Prefetch only scores >=10 for each user filtered_scores = Prefetch( 'score', queryset=Score.objects.filter(score__gte=10), to_attr='filtered_scores' ) # Optional: Add a filter to only return users who have at least one valid score return User.objects.prefetch_related(filtered_scores)
Then update your serializer.py to use the prefiltered attribute:
class UserDetailsSerializer(serializers.ModelSerializer): score = serializers.StringRelatedField(many=True, source='filtered_scores') class Meta: model = User fields = ('id', 'score', )
Key Notes:
StringRelatedFielduses the__str__method of yourScoremodel under the hood. Make sure yourScoremodel has a__str__defined (e.g.,def __str__(self): return str(self.score)), otherwise you'll get the default object representation.- The
Prefetchapproach is better for performance because it reduces the number of database queries from N+1 to just 2 (one for users, one for filtered scores).
内容的提问来源于stack exchange,提问作者Sakthi Panneerselvam

