假设我有以下Django模型:
class Account(models.Model):
name = models.CharField()
class Payment(models.Model):
account = models.ForeignKey(Account)
amount = models.FloatField()
date = models.DateField()
person = models.ForeignKey(User)
我有各种帐户,各种人都可以在帐户中付款。我想显示一个帐户列表,并显示谁支付了最后一笔款项,金额和日期是多少。像这样的东西(不知道如何在这里添加一个合适的表):
帐户|最后一笔付款由|上次付款日期
食物|彼得| 2018年2月3日饮料|约翰| 2018年2月10日
如何通过一次或两次查询实现此目的?也许通过一些花哨的预取/注释,但我无法弄明白。我可以使用注释+最大值来获取最后一个日期,但我如何获得付款人?
否则我只需要查询每一行。如果我将帐号的数量限制为50,那么我认为50个查询不是很糟糕,但仍然不理想。
答案 0 :(得分:2)
如果Payment
ID是连续的并且它始终与日期字段匹配,那么从某种意义上说,最新付款总是获得最新的ID,您可以使用两个查询来执行此操作:
from django.db.models import Max
last_payments_ids = Payment.objects \
.values('account_id') \
.annotate(last_payment_id=Max('id')) \
.values_list('last_payment_id', flat=True)
last_payment_per_account = Payment.objects \
.select_related('account', 'person') \
.filter(id__in=last_payments_ids)
请注意,我使用account_id
按表达式创建了一个组,然后Max('id')
应用于Payment
的ID,而不是Account
1}}。
只需两个查询,无论记录多少:
{% for payment in last_payment_per_account %}
<td>{{ payment.account.name }}</td>
<td>{{ payment.person.first_name }}</td>
<td>{{ payment.date }}</td>
{% endfor %}
答案 1 :(得分:0)
根据您正在处理的记录数量(例如,除非数百万),我认为不需要任何注释或自定义SQL:
recent_payments = Payment.objects.order_by('-date').select_related("account")
或者如果您想要上一个付款对象,可以按latest()
recent_payments = Payment.objects.order_by('-date').latest().select_related("account")
然后直接浏览结果:
for payment in recent_payments:
col1 = payment.account.name # eg "Food"
col2 = payment.person.first_name # eg "John"
col3 = payment.date.strftime("-%d %B %Y") # eg "10 Feb 2018"
请记住将db_index = True添加到日期字段,因为您要对该字段进行排序,并且在未编制索引的字段上排序要慢得多。
编辑:道歉,我误读了最初的问题,认为这是所有付款的记录。上述答案优雅地完成了OP最初要求的工作。