[英]Count events types per day for different timezones using Django ORM
我們有一個包含多個事件以及添加時間的表。 用於存儲事件的默認時區是 UTC。 例如:
class Events:
type = models.CharField(max_length=45, null=False)
date_added = models.DateTimeField(auto_now_add=True)
現在,我們想要獲取兩個日期之間不同事件類型的每日計數 - start_date 和 end_date。 例如:對於 start_date = "2020-03-1" 和 end_date = "2020-03-31",output 應該是 -
[{
"date" : "2020-03-1",
"event1" : 200,
"event2" : 606,
"event3" : 595
},
{
"date" : "2020-03-2",
"event1" : 357,
"event2" : 71,
"event3" : 634
},
{
"date" : "2020-03-3",
"event1" : 106,
"event2" : 943,
"event3" : 315
},
{
"date" : "2020-03-4",
"event1" : 187,
"event2" : 912,
"event3" : 743
},
.
.
.
.
{
"date" : "2020-03-31",
"event1" : 879,
"event2" : 292,
"event3" : 438
}]
由於用戶位於不同的時區(美國、歐洲、亞洲等),我們希望在計算事件之前根據用戶轉換時區。 以 UTC 計數在用戶的時區中每天都會有錯誤的計數。 例如:在 3 月 3 日凌晨 1 點 30 分在 IST 創建的事件將在 3 月 2 日晚上 8 點(UTC 時間)顯示並相應計數。
如果我們使用for循環,它會變得非常昂貴。 因此,我們希望使用 Django ORM 在 DB 級別執行此操作。 如果不可能完全依賴 Django ORM,我們希望使其盡可能高效。
我們能想到的最好的查詢是:
Events.objects.filter(
pk = user_pk, date__range = (
(end_date - time_delta).strftime("%Y-%m-%d"),
end_date.strftime("%Y-%m-%d")
)
).extra({
"date_added" : "date(date_added)"
}).values(
"date_added",
"type"
).annotate(
models.Count("type")
)
我們得到的結果如下:
<QuerySet [{'date_added': datetime.date(2020, 3, 6), 'type': 'event1', 'type__count': 30},
{'date_added': datetime.date(2020, 3, 6), 'type': 'event2', 'type__count': 189},
{'date_added': datetime.date(2020, 3, 6), 'type': 'event3', 'type__count': 1},
{'date_added': datetime.date(2020, 3, 6), 'type': 'event4', 'type__count': 3},
{'date_added': datetime.date(2020, 3, 9), 'type': 'event2', 'type__count': 57},
{'date_added': datetime.date(2020, 3, 9), 'type': 'event1', 'type__count': 23},
{'date_added': datetime.date(2020, 3, 9), 'type': 'event4', 'type__count': 1},
{'date_added': datetime.date(2020, 3, 10), 'type': 'event1', 'type__count': 5},
{'date_added': datetime.date(2020, 3, 10), 'type': 'event2', 'type__count': 21},
{'date_added': datetime.date(2020, 3, 11), 'type': 'event2', 'type__count': 9},
{'date_added': datetime.date(2020, 3, 11), 'type': 'event1', 'type__count': 15},
{'date_added': datetime.date(2020, 3, 12), 'type': 'event2', 'type__count': 49},
{'date_added': datetime.date(2020, 3, 13), 'type': 'event2', 'type__count': 8},
{'date_added': datetime.date(2020, 3, 13), 'type': 'event1', 'type__count': 3},
{'date_added': datetime.date(2020, 3, 17), 'type': 'event1', 'type__count': 16},
{'date_added': datetime.date(2020, 3, 17), 'type': 'event2', 'type__count': 26},
{'date_added': datetime.date(2020, 3, 17), 'type': 'event4', 'type__count': 1},
{'date_added': datetime.date(2020, 3, 17), 'type': 'event3', 'type__count': 1},
{'date_added': datetime.date(2020, 3, 18), 'type': 'event2', 'type__count': 64},
{'date_added': datetime.date(2020, 3, 18), 'type': 'event1', 'type__count': 11},
'...(remaining elements truncated)...']>
這仍然需要一個for循環來將具有相同日期的所有事件添加到一個字典中,但時區問題仍然存在。
如何解決這個問題?
我們終於能夠解決這個問題。 我們仍在使用 for 循環來獲取所需格式的數據,但我們能夠將繁重的工作轉移到數據庫。 首先是以下幾點:
我正在使用 MySQL DB。 (檢查下面的點,看看為什么這是相關的。)
如果您想直接使用時差轉換時區(IST 為“+05:30”,UTC 為“+00:00”),則無需運行任何命令。
這是 Django ORM 查詢:
events_list = Events.objects.all().extra(
{
"date_added" : "date(CONVERT_TZ(date_added, 'UTC', 'America/Chicago'))"
}
).values(
"date_added",
"type"
).annotate(
models.Count(
"type"
)
)
這將提供以下格式的數據:
<QuerySet [{'date_added': datetime.date(2020, 3, 6), 'type': 'event1', 'type__count': 31},
{'date_added': datetime.date(2020, 3, 6), 'type': 'event2', 'type__count': 189},
{'date_added': datetime.date(2020, 3, 6), 'type': 'event3', 'type__count': 1},
{'date_added': datetime.date(2020, 3, 6), 'type': 'event4', 'type__count': 3},
{'date_added': datetime.date(2020, 3, 9), 'type': 'event2', 'type__count': 58},
{'date_added': datetime.date(2020, 3, 9), 'type': 'event1', 'type__count': 21},
{'date_added': datetime.date(2020, 3, 9), 'type': 'event4', 'type__count': 1},
{'date_added': datetime.date(2020, 3, 10), 'type': 'event1', 'type__count': 1},
{'date_added': datetime.date(2020, 3, 10), 'type': 'event2', 'type__count': 23},
{'date_added': datetime.date(2020, 3, 11), 'type': 'event2', 'type__count': 10},
{'date_added': datetime.date(2020, 3, 11), 'type': 'event1', 'type__count': 16},
{'date_added': datetime.date(2020, 3, 12), 'type': 'event2', 'type__count': 50},
{'date_added': datetime.date(2020, 3, 13), 'type': 'event2', 'type__count': 10},
{'date_added': datetime.date(2020, 3, 13), 'type': 'event1', 'type__count': 1},
{'date_added': datetime.date(2020, 3, 17), 'type': 'event1', 'type__count': 19},
{'date_added': datetime.date(2020, 3, 17), 'type': 'event2', 'type__count': 27},
{'date_added': datetime.date(2020, 3, 17), 'type': 'event4', 'type__count': 3},
{'date_added': datetime.date(2020, 3, 17), 'type': 'event3', 'type__count': 1},
{'date_added': datetime.date(2020, 3, 18), 'type': 'event2', 'type__count': 61},
{'date_added': datetime.date(2020, 3, 18), 'type': 'event1', 'type__count': 13},
'...(remaining elements truncated)...']>
此處在轉換時區后計算特定事件的數量。 現在,一旦我們在時區轉換后獲得了事件的計數,剩下的就是以所需的格式獲取這些數據,這可以通過for循環輕松完成。
PS:
如果您對查詢有任何條件,則可以使用 filter() 代替 all。 例如:
from django.utils import timezone Events.objects.filter( type__in = ["event1", "event2"], date__gt = ( timezone.now() - timezone.timedelta(days = 30) ) ).extra( { "date_added": "date(CONVERT_TZ(date_added, 'UTC', 'ASIA/KOLKATA'))" } ).values( "date_added", "type" ).annotate( models.Count( "type" ) )
這將為事件類型 1 和 2 提供過去 30 天的數據。
您可以對 UTC 使用“+00:00”,對 ASIA/KOLKATA 使用“+05:30”。 例如:“date_added”:“date(CONVERT_TZ(date_added, '+00:00', '+05:30'))”
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.