如何在Django中按指定多对多关联的MovieTranslation排序?
解决方案:按指定语言的翻译标题排序Django Movie模型
要实现按lang='en'的MovieTranslation的title对Movie排序,核心是先精准关联到目标语言的翻译记录,再基于该记录的字段排序。以下是两种可行的实现方式,均在FilterSet类中完成:
方法一:使用FilteredRelation(Django 2.0+)
FilteredRelation可以创建一个过滤后的关联关系,仅包含符合条件的MovieTranslation实例,再通过该关联提取标题用于排序:
from django.db.models import FilteredRelation, Q from django_filters import FilterSet, OrderingFilter class MovieFilter(FilterSet): # 定义排序字段,前端可通过?ordering=title_en触发排序 ordering = OrderingFilter( fields=( ('english_title', 'title_en'), ) ) class Meta: model = Movie fields = [] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 标注当前Movie对应的英文翻译标题 self.queryset = self.queryset.annotate( english_title=FilteredRelation( 'movie_translations', condition=Q(movie_translations__lang='en') ).title )
方法二:使用Subquery + OuterRef(兼容更早Django版本)
通过子查询针对每个Movie单独获取其英文翻译的标题,避免多对多关联导致的排序混乱:
from django.db.models import Subquery, OuterRef from django_filters import FilterSet, OrderingFilter class MovieFilter(FilterSet): ordering = OrderingFilter( fields=( ('english_title', 'title_en'), ) ) class Meta: model = Movie fields = [] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 子查询:获取当前Movie的第一条英文翻译标题 en_title_subquery = MovieTranslation.objects.filter( movie=OuterRef('pk'), lang='en' ).values('title')[:1] self.queryset = self.queryset.annotate( english_title=Subquery(en_title_subquery) )
后续配置与注意事项
- 关联ViewSet:在你的
MovieViewSet中指定该FilterSet:
from rest_framework import viewsets class MovieViewSet(viewsets.ModelViewSet): queryset = Movie.objects.all() filter_class = MovieFilter # 其他如serializer_class等配置...
- 过滤无英文翻译的Movie:如果需要仅保留有英文翻译的条目,可在annotate前添加过滤:
self.queryset = self.queryset.filter(movie_translations__lang='en').annotate(...)
- 处理空值排序:若存在无英文翻译的Movie,
english_title会为Null,不同数据库对Null值的排序逻辑不同(如PostgreSQL会将Null排在末尾),可根据需求调整。
内容的提问来源于stack exchange,提问作者Triarier
相关产品推荐
相关产品推荐

