0

我已经构建了以下查询/(IES):

users = User.objects.filter(is_active=True)

date_range = [start_date, timezone.now()]

results = SurveyResult.objects.filter(
    user__in=users,
    created_date__range=date_range,
).annotate(
    date=TruncDate('created_date'),
    total_score=Sum('score'),
    participants=Count('user'),
).values(
    'survey',
    'user',
    'date',
    'total_score',
    'participants',
).order_by(
    'date',
)

将生成的 QuerySet 中的每个结果快速打印为:

for result in results:
    print(results)

...输出数据如下:

{'survey': UUID('eb51368e-994a-4c0b-8d8a-e00ed20b5926'), 'user': UUID('25afbbfd-bddf-4fe8-bbac-758bd96093b0'), 'date': datetime.date(2019, 7, 26), 'total_score': 90, 'participants': 1}
{'survey': UUID('09947780-8d60-499f-87e3-fc53a9490960'), 'user': UUID('6afdea22-ea10-4069-9e7b-43fb6955ce0e'), 'date': datetime.date(2019, 7, 26), 'total_score': 17, 'participants': 1}
{'survey': UUID('890d0a21-6e27-457f-902e-e2f37d2fad6c'), 'user': UUID('d98684f7-97ab-49d7-be50-0cc9b6465ef5'), 'date': datetime.date(2019, 7, 26), 'total_score': 35, 'participants': 1}
{'survey': UUID('890d0a21-6e27-457f-902e-e2f37d2fad6c'), 'user': UUID('d98684f7-97ab-49d7-be50-0cc9b6465ef5'), 'date': datetime.date(2019, 7, 27), 'total_score': 62, 'participants': 1}

眼尖的您可能会注意到最后两条记录在“用户”和“调查”键上是伪重复的,但在其他任何键上都没有。

我的问题是:我到底如何从这个记录集中删除记录(使用我构建的Django ORM查询或以标准的pythonic方式),其中“调查”和“用户”键匹配 - 只保留最新的根据“日期”记录......所以离开我:

预期结果:

{'survey': UUID('eb51368e-994a-4c0b-8d8a-e00ed20b5926'), 'user': UUID('25afbbfd-bddf-4fe8-bbac-758bd96093b0'), 'date': datetime.date(2019, 7, 26), 'total_score': 90, 'participants': 1}
{'survey': UUID('09947780-8d60-499f-87e3-fc53a9490960'), 'user': UUID('6afdea22-ea10-4069-9e7b-43fb6955ce0e'), 'date': datetime.date(2019, 7, 26), 'total_score': 17, 'participants': 1}
{'survey': UUID('890d0a21-6e27-457f-902e-e2f37d2fad6c'), 'user': UUID('d98684f7-97ab-49d7-be50-0cc9b6465ef5'), 'date': datetime.date(2019, 7, 27), 'total_score': 62, 'participants': 1}

我尝试过的事情

我在想也许利用这样的东西:

unique = { result['survey'] and result['user'] : result for result in results }.values()
4

1 回答 1

0

你显然已经有了你想要的结果,所以你也可以在 python 中做到这一点,这几乎是你提出的:

unique = {f"{result['survey']}+{result['user']}": result for result in results}.values()

您的尝试不起作用的原因是:您应该使用代表调查和用户的唯一键。随着and你刚刚得到result['user'],如果两者都是,a and b将返回。bTrue

但是,我相信您的 ORM 查询有问题。您需要确保获得latest_score特定用户给出的分数,而不是给出分数的最后一天的分数之一(假设您有两个不同created_date(不同时间)的分数,但在 之后TruncDate,它们具有相同的date)。为了得到最后的分数,你应该试试这个:

results = SurveyResult.objects.filter(
    user__in=users,
    created_date__range=date_range,
).values(
    'survey', 'user'  # group by unique survey, user pair
).annotate(last_score=
    Window(expression=LastValue('score'),
           partition_by=[F('user'), F('survey')],
           order_by=F('created_date').asc(),
    )
).annotate(date=
    Window(expression=LastValue(TruncDate('created_date')),
           partition_by=[F('user'), F('survey')],
           order_by=F('created_date').asc(),
    )
).values(
    'survey', 'user', 'date', 'last_score'
)

total_score并且participants没有真正的意义,因为分数只是用户最后一次为特定调查评分的那一行;参与者总是1。

如果您按调查和日期而不是调查和用户进行汇总,这些将是有意义的。

于 2019-08-07T13:47:19.143 回答