簡體   English   中英

使用 Django ORM 每天計算不同時區的事件類型

[英]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 循環來獲取所需格式的數據,但我們能夠將繁重的工作轉移到數據庫。 首先是以下幾點:

  1. 我正在使用 MySQL DB。 (檢查下面的點,看看為什么這是相關的。)

  2. 如果您想直接使用時差轉換時區(IST 為“+05:30”,UTC 為“+00:00”),則無需運行任何命令。

  3. 但是,您需要運行命令以在 MySQL DB 中按名稱支持時區。 例如:如果您要使用命名時區(“ASIA/KOLKATA”或“UTC”),則需要運行一個命令:
    • mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -D mysql -u 根 -p
  4. 此命令適用於在 Ubuntu 中運行的 MySQL DB。 有類似的
    其他數據庫(如 Postgresql)和平台(如 Windows)的命令。

這是 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:

  1. 如果您對查詢有任何條件,則可以使用 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 天的數據。

  2. 您可以對 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM