通过进一步限制生成的查询集,该问题与Django ORM: filter primary model based on chronological fields from related model远程相关。
假设我们有以下型号:
class Patient(models.Model)
name = models.CharField()
# other fields following
class MedicalFile(model.Model)
patient = models.ForeignKey(Patient, related_name='files')
issuing_date = models.DateField()
expiring_date = models.DateField()
diagnostic = models.CharField()
我需要选择在指定日期有效的所有文件,最有可能是过去的文件。我在这里遇到的问题是,对于每个患者,将会有一个小的重叠期,患者将有2个有效文件。如果我们要查询那个小时间段的日期,我只需要选择最新的文件。
更重要的是:考虑患者John Doe。他将拥有从2012年开始的一系列“不间断”文件,如下所示:
+---+------------+-------------+
|ID |issuing_date|expiring_date|
+---+------------+-------------+
|1 |2012-03-06 |2013-03-06 |
+---+------------+-------------+
|2 |2013-03-04 |2014-03-04 |
+---+------------+-------------+
|3 |2014-03-04 |2015-03-04 |
+---+------------+-------------+
正如人们可以很容易地观察到的那样,这些文件的有效性存在几天的重叠。例如,在2013-03-05,文件1和2是有效的,但我们只考虑文件2(作为最新文件)。我猜这个用例并不特别:这是管理订阅的情况,为了获得连续订阅,您需要提前续订。
现在,在我的应用程序中,我需要查询历史数据,例如给我所有在2013-03-05有效的文件,只考虑“最近的”文件。我能够通过使用RawSQL来解决这个问题,但我希望有一个没有原始SQL的解决方案。在上一个问题中,我们能够通过反向关系聚合过滤“最新”文件,如:
qs = MedicalFile.objects.annotate(latest_file_date=Max('patient__files__issuing_date'))
qs = qs.filter(issuing_date=F('latest_file_date')).select_related('patient')
问题是我们需要通过对2013-03-05进行过滤来限制计算latest_file_date的范围。但是聚合函数不会在筛选的查询集上运行...
我目前正在通过额外的queryset子句(用您的具体应用程序替换“app”)来执行此操作:
reference_date = datetime.date(year=2013, month=3, day=5)
annotation_latest_issuing_date = {
'latest_issuing_date': RawSQL('SELECT max(file.issuing_date) '
'FROM <app>_medicalfile file '
'WHERE file.person_id = <app>_medicalfile.person_id '
' AND file.issuing_date <= %s', (reference_date, ))
}
qs = MedicalFile.objects.filter(expiring_date__gt=reference_date, issuing_date__lte=reference_date)
qs = qs.extra(**annotation_latest_issuing_date).filter(issuing_date=F('latest_issuing_date'))
这样写,查询集返回正确的记录数。
问题:如果没有RaWSQL和(已经隐含)具有相同的性能水平,怎么能实现?
答案 0 :(得分:0)
考虑p
是一个Patient类实例。
我认为你可以这样做:
p.files.filter(issue_date__lt='some_date', expiring_date__gt='some_date')
请参阅https://docs.djangoproject.com/en/1.9/topics/db/queries/#backwards-related-objects
或者使用Q
魔术查询对象...
答案 1 :(得分:0)
您可以使用id__in
并提供嵌套的过滤查询集(就像在给定日期有效的所有文件一样)。
qs = MedicalFile.objects
.filter(id__in=self.filter(expiring_date__gt=reference_date, issuing_date__lte=reference_date))
.order_by('patient__pk', '-issuing_date')
.distinct('patient__pk') # field_name parameter only supported by Postgres
order_by
按病人分组文件,最先发布日期。然后distinct
检索每个患者的第一个文件。但是,在合并order_by
和distinct
:https://docs.djangoproject.com/en/1.9/ref/models/querysets/#django.db.models.query.QuerySet.distinct
修改:从第一次过滤删除了单个患者依赖,并将latest
更改为order_by
和distinct
的组合