Django - 左连接日期数组与查询集

Django - left joining date array with a queryset

在我的 Django 项目中,我有以下模型:

class Examine(models.Model):
         name = models.CharField(max_length=45)
         date = models.DateField(blank=True, null=True)

我的目标是想出一个查询集,使我能够呈现一个包含日期列表和检查日期(如果有的话)的模板。例如,我在数据库中有三个检查:

Math - 01 January 2019, 
History - 03 January 2019
Geoghraphy - 03 January 2019

我对 2019 年 1 月 1 日至 1 月 4 日这一日期区间感兴趣。 输出应该是:

January 1
     Math
January 2
     No exams
January 3
     History
     Geography
January 4
     No exams

我有两年使用 Django ORM 的经验,但我什至无法提交我尝试实现它的任何尝试。我没有想法。在 Django 中可以吗?

从您知道的可能开始 - 使用 in the docs here 中所述的日期范围过滤器从数据库中获取考试。

from datetime import date

start_date = date(2019, 1, 1)
end_date = date(2019, 1, 4)
exams = Examine.objects.filter(date__gte=start_date, date__lte=end_date).order_by('date')

我认为您可能对使用日期进行 'left join' 的想法感到困惑。这在原始 SQL 查询中是可能的,但在这里没有必要。

本质上,我们要做的是在从相关日期范围获取考试后,在 Python 代码中执行左连接操作。

让我们创建一个可以支持我们想要做的数据结构:

from collections import defaultdict

exams_by_day = defaultdict(list)
for exam in exams:
    exams_by_day[exam.date].append(exam)

因为它是一个 defaultdict,如果我们访问一个不存在的键,我们将得到一个空列表。

最后一块是为左列生成日期列表:

from datetime import timedelta

date_diff = end - start  # a timedelta object (3 days)
dates = []
for i in range(date_diff.days + 1):
    dates.append(start + timedelta(days=i))

最后我们可以将这两个数据结构传递到我们的模板中并迭代它们以生成您想要的输出:

<dl>
{% for date_ in dates %}
    <dt>{{ date_|date:"F j"}}</dt>
    <dd>
        <ol>
        {% with exams=exams_by_date.date %}
        {% for exam in exams %}
            <li>{{ exam.name }}</li>
        {% empty %}
            <li>No exams</li>
        {% endfor %}
        </ol>
    </dd>
{% endfor %}
</dl>

https://docs.djangoproject.com/en/2.0/ref/templates/builtins/
有关上述 with|date:"F j" 的详细信息。