如何按关联模型中指定类型文档的上传时间对Item QuerySet排序?
解决Django中仅按特定关联模型字段排序的问题
你的问题核心是:在获取当前用户的Item集合时,需要只基于doc_type为"DOC"的Document的uploaded_at字段排序,但原代码的order_by("docs__uploaded_at")会关联所有关联的Document(包括非DOC类型),导致排序逻辑不符合预期。
以下是两种可行的解决方案:
方案一:使用FilteredRelation过滤关联模型(Django 2.0+)
通过FilteredRelation创建一个仅包含符合条件的Document的关联,再基于这个过滤后的关联字段排序:
from django.db.models import FilteredRelation, Q from django.db.models import Prefetch @api_view(["GET"]) def get_items(request): items = Item.objects.filter(user=request.user) \ # 创建过滤后的关联,仅包含doc_type="DOC"的Document .annotate( filtered_doc=FilteredRelation( 'docs', condition=Q(docs__doc_type="DOC") ) ) \ # 基于过滤后的文档的uploaded_at排序 .order_by("filtered_doc__uploaded_at") \ # 可选:预取过滤后的文档,避免后续查询冗余数据 .prefetch_related( Prefetch( 'docs', queryset=Document.objects.filter(doc_type="DOC"), to_attr='filtered_docs' ) ) # 此处替换为你实际的序列化逻辑 return Response(YourItemSerializer(items, many=True).data)
方案二:使用子查询获取目标排序字段
通过子查询为每个Item提取对应的DOC类型Document的uploaded_at,再基于这个字段排序:
from django.db.models import Subquery, OuterRef from django.db.models import Prefetch @api_view(["GET"]) def get_items(request): # 子查询:获取当前Item下最新的DOC类型文档的上传时间 latest_doc_uploaded = Document.objects.filter( item=OuterRef('pk'), doc_type="DOC" ).order_by('-uploaded_at').values('uploaded_at')[:1] items = Item.objects.filter(user=request.user) \ # 为每个Item标注对应的DOC文档上传时间 .annotate(latest_doc_uploaded_at=Subquery(latest_doc_uploaded)) \ # 基于标注的字段排序,可通过nulls_last控制无DOC文档的Item位置 .order_by("latest_doc_uploaded_at") \ # 可选:预取过滤后的文档 .prefetch_related( Prefetch( 'docs', queryset=Document.objects.filter(doc_type="DOC"), to_attr='filtered_docs' ) ) # 此处替换为你实际的序列化逻辑 return Response(YourItemSerializer(items, many=True).data)
原代码问题说明
原代码中order_by("docs__uploaded_at")会执行左连接,关联当前Item的所有Document记录,排序时会把所有关联文档的uploaded_at都纳入考虑,导致排序逻辑不符合“仅DOC类型”的需求。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

