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

Django入门:按属性及日期排序QuerySet遇报错求解决

解决方案

错误原因分析

  1. 第一种方案报错是因为sorted()返回的是Python列表,而ModelViewSet要求queryset必须是Django的QuerySet实例,列表没有model属性,导致报错。
  2. 第二种方案有两个问题:
    • 计算has_ended的逻辑错误,F('start_date')-F('end_date')是日期差值,不是判断项目是否结束的逻辑。
    • 注解字段名has_ended与模型中的@property重名,Django尝试给模型实例赋值该属性,但@property是只读的,因此抛出AttributeError。

正确实现方式

推荐使用数据库层面的注解排序,效率更高且符合ModelViewSet的要求:

步骤1:导入必要模块

from django.db.models import Case, When, BooleanField, Value
from django.utils import timezone

步骤2:构造正确的QuerySet

class ProjectViewSet(viewsets.ModelViewSet):
    serializer_class = ProjectSerializer
    permission_classes = [permissions.IsAuthenticated]

    def get_queryset(self):
        return Project.objects.annotate(
            # 用is_ended作为别名,避免和模型的has_ended属性冲突
            is_ended=Case(
                # 判断条件:end_date不为空且小于当前日期
                When(end_date__isnull=False, end_date__lt=timezone.now().date(), then=Value(True)),
                default=Value(False),
                output_field=BooleanField()
            )
        ).order_by('is_ended', '-start_date')

逻辑说明

  • Case/When在数据库层面计算项目是否已结束,生成is_ended布尔字段。
  • 排序时,is_ended为False(未结束)的项目会排在前面(布尔值排序中False对应0,True对应1),再按start_date倒序排列,完全符合需求。

备选方案(不推荐)

如果必须用Python层面排序,需在get_queryset中返回排序后的列表,但会丢失Django QuerySet的分页、过滤等功能:

def get_queryset(self):
    qs = Project.objects.all().order_by('-start_date')
    # 按has_ended排序,未结束(False)在前,已结束(True)在后
    return sorted(qs, key=lambda project: project.has_ended)

内容的提问来源于stack exchange,提问作者Guillermo Lupiáñez Tapia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 01:21:05