我一直在使用Django ORM中的新聚合功能,并且我认为应该是可能的一类问题,但我似乎无法让它工作。我正在尝试生成的查询类型为here。
所以,假设我有以下模型 -
class ContactGroup(models.Model):
.... whatever ....
class Contact(models.Model):
group = models.ForeignKey(ContactGroup)
name = models.CharField(max_length=20)
email = models.EmailField()
...
class Record(models.Model):
contact = models.ForeignKey(Contact)
group = models.ForeignKey(ContactGroup)
record_date = models.DateTimeField(default=datetime.datetime.now)
... name, email, and other fields that are in Contact ...
因此,每次创建或修改联系人时,都会创建一个新记录,用于保存当时在联系人中显示的信息以及时间戳。现在,我想要一个查询,例如,返回与ContactGroup关联的每个联系人的最新Record实例。在伪代码中:
group = ContactGroup.objects.get(...)
records_i_want = group.record_set.most_recent_record_for_every_contact()
一旦我理解了这一点,我只想在查询集上抛出filter(record_date__lt=some_date)
,并获取some_date
中存在的信息。
有人有什么想法吗?
编辑:我似乎并没有真正说清楚。使用这些模型,我想用纯django ORM(没有额外的())来做一些方法:
ContactGroup.record_set.extra(where=["history_date = (select max(history_date) from app_record r where r.id=app_record.id and r.history_date <= '2009-07-18')"])
将子查询放在where子句中只是解决这个问题的一种策略,其他的很好地覆盖了我上面给出的第一个链接。我知道如果不使用extra(),where子句子选择是不可能的,但我想也许新的聚合功能可能使其他方法成为可能。
答案 0 :(得分:0)
听起来你想在Django中记录对象的变化。
Pro Django在第11章(增强应用程序)中有一节,其中作者展示了如何创建一个模型,该模型使用另一个模型作为它跟踪插入/删除/更新的客户端。模型是动态生成的从客户端定义并依赖于信号。代码显示了most_recent()函数,但您可以对此进行调整以获取特定日期的对象状态。
我认为Django中的跟踪存在问题,而不是获取此问题的SQL,对吗?
答案 1 :(得分:0)
首先,我要指出:
ContactGroup.record_set.extra(where=["history_date = (select max(history_date) from app_record r where r.id=app_record.id and r.history_date <= '2009-07-18')"])
不会给你带来与以下相同的效果:
records_i_want = group.record_set.most_recent_record_for_every_contact()
第一个查询返回与特定组相关联的每个记录(或与特定组的任何联系人关联),其记录的记录小于额外中指定的日期/时间。在shell上运行它,然后执行此操作以查看创建的查询django:
from django.db import connection
connection.queries[-1]
揭示:
'SELECT "contacts_record"."id", "contacts_record"."contact_id", "contacts_record"."group_id", "contacts_record"."record_date", "contacts_record"."name", "contacts_record"."email" FROM "contacts_record" WHERE "contacts_record"."group_id" = 1 AND record_date = (select max(record_date) from contacts_record r where r.id=contacts_record.id and r.record_date <= \'2009-07-18\')
不完全是你想要的,对吧?
现在,聚合功能用于检索聚合数据,而不是与聚合数据关联的对象。因此,如果您尝试在尝试获取 group.record_set.most_recent_record_for_every_contact()时尽量减少使用聚合执行的查询数量,那么您将无法成功。
不使用聚合,您可以使用以下方式获取与组关联的所有联系人的最新记录:
[x.record_set.all().order_by('-record_date')[0] for x in group.contact_set.all()]
使用聚合,我能得到的最接近的是:
group.record_set.values('contact').annotate(latest_date=Max('record_date'))
后者返回一个词典列表,如:
[{'contact': 1, 'latest_date': somedate }, {'contact': 2, 'latest_date': somedate }]
因此,给定组中每个联系人的一个条目以及与之关联的最新记录日期。
无论如何,最小查询号可能是组中联系人的1 +#。如果您有兴趣使用单个查询获得结果,那也是可能的,但您必须以不同的方式构建模型。但这是你问题的一个完全不同的方面。
我希望这有助于您了解如何使用聚合/常规ORM函数来解决问题。