Django ORM:按相关表的过滤器的聚合排序

时间:2012-10-30 11:19:43

标签: python sql django orm django-models

这是我模型的一个子集:

class Case(models.Model):
    ... # primary key is named "id"
class Employee(models.Model):
    ... # primary key is named "id"
class Report(models.Model):
    case = ForeignKey(Case, null=True)
    employee = ForeignKey(Employee)
    date = DateField()

鉴于某个特定员工,我想生成所有案例的列表,按员工最近报告的时间排序。那些没有报告的案例应该排在最后。同一日期的案例(包括NULL)应按其他标准排序。

我可以在Django ORM api中表达这个吗?如果是这样,怎么样?

在伪SQL中,我想我想要

Select Case.*
From Case some-kind-of-join Report
Where report.employee_id = the_given_employee_id
Group by Case.id
Order by Max(Report.date) Desc /* Report-less cases last */, Case.id /* etc. */

我是否需要通过报告在Case to Employee中引入多对多关系,以便在Django ORM中执行此操作?

1 个答案:

答案 0 :(得分:0)

django模型中的每个关系都有a reverse relationship that can be easily queried(包括订购时),所以你可以这样做:

Case.objects.all().order_by('-report__date', 'another_field', 'a third field')

但是这不会为您提供有关单个特定员工的任何信息。你可以这样做:

Case.objects.filter(report__employee__pk=5).order_by('-report__date', 'another_field', 'a third field')

但这不会返回任何未由您的特定员工编辑的Case个对象。

所以遗憾的是,您不能原生地执行子查询,因此您必须编写自定义注释查询,以便执行子查询(即特定员工最后编辑的那些对象的最后订单日期)。这是未经测试的,但这是一般的想法:

Case \
    .objects \
    .all() \
    .extra(select = {
        "employee_last_edit" : """
            SELECT app_report.date
            FROM app_report
                JOIN app_case ON app_case__id = app_report.case_id
            WHERE app_report.employee_id = %d
        """ % employee.id }) \
    .order_by('-employee_last_edit' , 'something_else')