Django ORM 使用 where 子句按组过滤

Django ORM filter by group with where clause

我有学生的榜样和意见。随着时间的推移,每个学生都可以改变他们的观点。我最终想做的是创建一个图表,显示在给定日期持有每种意见的学生人数,但作为第一步,我想计算在给定日期持有每种意见的学生人数。

我的模型如下(为简洁起见缩写):

class Student(models.Model):
    first_name = models.CharField(max_length=30, null=True, blank=True)
    surname = models.CharField(max_length=30, null=True, blank=True)


class Opinion(models.Model):
    student = models.ForeignKey('Student', on_delete=models.CASCADE,null=True)

    opdate = models.DateField(null=True, blank=True)
    sentiment_choice = [
    ('Positive', 'Positive'),
    ('Negative', 'Negative'),
    ]   
    sentiment = models.CharField(
        max_length=40,
        choices=sentiment_choice,
        default="Positive",
        null=True, blank=True
    )           

我的方法是遍历一个范围内的所有日期,过滤意见 table 以获得截至该日期的所有数据,找到每个学生的最新意见,计算这些并将结果加载到数组。

我知道如何过滤意见 table 如下(其中 start_date 是我的迭代器):

Opinion.objects.filter(opdate__lte=start_date)

我也知道如何获取每个学生的最新意见:

 Opinion.objects.values('student').annotate(latest_date=Max('opdate'))

我如何将其结合起来,以便我可以获得迭代器之前每个学生的最新意见?

我正在使用 SQL Lite DB

开发 Django 3.2.12

您可以将 Subquery expression [Django-doc] 用于:

from django.db.models import OuterRef, Subquery

Student.objects.annotate(
    last_sentiment=<b>Subquery(</b>
        Opinion.objects.filter(
            <b>student_id=OuterRef('pk')</b>
        ).order_by('-opdate').values('sentiment')[:1]
    <b>)</b>
)

Students 将有一个额外的属性 .last_sentiment,它将包含最后一个相关 Opinion 记录的 sentiment,或 NULL/None 如果没有相关的 Opinion.