django - Django:填补按月分组的视图中的空白
问题描述
我的问题似乎很标准,我找到了很多解决方案,但没有一个适用于 Django 视图。
我有带时间戳的项目(“转换”),我想显示每月的项目数量。我的观点是这样的:
2020-05 3
2020-03 2
我需要的是这个:
2020-05 3
2020-04 0
2020-03 2
模型.py:
class Conversion(models.Model):
timestamp = models.DateTimeField()
views.py (感谢这个帮助):
from django.db.models import Count
from django.db.models.functions import TruncMonth
def conversions_monthly(request):
conv = Conversion.objects.values(month=TruncMonth(
'timestamp')).annotate(count=Count('pk')).order_by('-month')
context = {'conversion': conv}
return render(request, 'dummy/conversions_monthly.html', context)
模板conversions_monthly.html:
{% extends "dummy/base.html" %}
{% block content %}
<table>
{% for c in conversion %}
<tr>
<td>{{ c.month |date:"Y-m" }}</td>
<td class="text-right">{{ c.count }}</td>
</tr>
{% endfor %}
</table>
{% endblock content %}
数据:
[
{
"model": "dummy.conversion",
"pk": 1,
"fields": {
"project": 1,
"timestamp": "2020-03-10T05:00:00Z"
}
},
{
"model": "dummy.conversion",
"pk": 2,
"fields": {
"project": 1,
"timestamp": "2020-03-12T17:00:00Z"
}
},
{
"model": "dummy.conversion",
"pk": 3,
"fields": {
"project": 1,
"timestamp": "2020-05-19T12:00:00Z"
}
},
{
"model": "dummy.conversion",
"pk": 4,
"fields": {
"project": 2,
"timestamp": "2020-05-20T16:10:03Z"
}
},
{
"model": "dummy.conversion",
"pk": 5,
"fields": {
"project": 1,
"timestamp": "2020-05-20T16:30:00Z"
}
}
]
我想,我必须以某种方式“聚合”最小和最大日期,并且需要类似的东西:
import datetime
from dateutil.relativedelta import relativedelta
result = []
max = date(2020, 5, 20)
min = date(2020, 3, 1)
current = min
while current <= max:
result.append(current)
current += relativedelta(months=1)
提供[datetime.date(2020, 3, 1), datetime.date(2020, 4, 1), datetime.date(2020, 5, 1)]
我不知道如何将这些部分组合在一起——或者在 Django 中有完全不同的方法吗?
解决方案
您已经走在正确的道路上,这是您拼接在一起的代码
# views.py
def index(request):
result = []
# `min` and `max` are keywords in python, so it is bad practice to use them as variable names
_max = datetime.date(2020, 5, 20)
_min = datetime.date(2020, 3, 1)
current = _min
while current <= _max:
result.append({"date": current, "count": 0})
current += relativedelta(months=1)
conversions = Conversion.objects.values(month=TruncMonth(
'timestamp')).annotate(count=Count('pk')).order_by('-month')
# the conditions for checking `i` being smaller than `length` protect you in case there are no conversions in your range
i = 0
length = len(result)
for conversion in conversions:
while i < length and \
not (
result[i]["date"].year == conversion["month"].year and
result[i]["date"].month == conversion["month"].month
):
i += 1
if i < length:
result[i]["count"] = conversion["count"]
context = {'conversion': result}
return render(request, 'dummy/conversions_monthly.html', context)
模板
{% extends "dummy/base.html" %}
{% block content %}
<table>
{% for c in conversion %}
<tr>
<td>{{ c.date |date:"Y-m" }}</td>
<td class="text-right">{{ c.count }}</td>
</tr>
{% endfor %}
</table>
{% endblock content %}
推荐阅读
- java - 由于 nextInt() 导致的 java.util.NoSuchElementException 类型的异常
- azure - 在 Azure 数据工厂中扩展 HTTP 并行副本
- java - 强制创建多个相同类型的对象
- node.js - 如何在 webpack 捆绑之前获取文件的 __dirname
- java - 堆栈中的内存分配和局部变量的删除
- python-3.x - 在python中计算较大数的幂的最有效方法是什么
- html - 如何将按钮插入 HTML 表格单元格
- android - 安装 apk 时出错:INSTALL PARSE_FAILED_NOT_APK
- cassandra - 在 Cassandra 中设置范围查询的主键
- excel - 如何基于一列导出多个excel