按月和日过滤 django 日期时间字段的问题

Posted

技术标签:

【中文标题】按月和日过滤 django 日期时间字段的问题【英文标题】:Problems filtering django datetime field by month and day 【发布时间】:2014-03-22 01:04:58 【问题描述】:

谁能向我解释为什么以下过滤器在月和日级别不起作用?按年份过滤似乎有效,但其他两个无效。

>>> clicks.count()
36
>>> date = clicks[0].created
>>> date.month
2
>>> date.year
2014
>>> date.day
1
>>> clicks.filter(created__month=2)
[]
>>> clicks.filter(created__month=02)
[]
>>> clicks.filter(created__month='02')
[]
>>> clicks.filter(created__month='2')
[]
>>> clicks.filter(created__month=date.month)
[]
>>> clicks.filter(created__day=date.day)
[]

快速更新以证明我在创建和处理查询集之前得到了相同的行为:

>>> clicks = PreviewClick.objects.filter(created__month = 2)
>>> clicks.count()
0
>>> clicks = PreviewClick.objects.filter(created__month = 02)
>>> clicks.count()
0
>>> clicks = PreviewClick.objects.filter(created__month = '02')
>>> clicks.count()
0
>>> clicks = PreviewClick.objects.filter(created__month = '2')
>>> clicks.count()
0

这里有更多值得深思的地方:

>>> clicks = PreviewClick.objects.all()
>>> counter = 0
>>> for click in clicks:
...      if click.created.month == 2:
...           counter += 1
... 
>>> counter
35

【问题讨论】:

你是如何创造点击的? 您确定您的点击日期为 2 月吗?我刚刚在我们的一个数据库上尝试了这个过滤器,对我来说效果很好。 看起来你做了 .objects.all() 并将其分配给点击,然后试图过滤它。你可能想做 .objects.filter(....) @user590028 在第二行中,我获取了查询集中第一项的实际“创建”值,并证明月份值实际上是二月。所以过滤器应该至少获得一条记录,对吗? 你能告诉我们PreviewClick.objects.all()里面有一个2个月的对象 【参考方案1】:

我看到的行为与您完全相同。

如果您检查 documentation 的 1.6 和月份查询集。他们添加了以下段落:

“当 USE_TZ 为 True 时,日期时间字段在过滤前转换为当前时区。这需要在数据库中定义时区。”

如果您将设置中的以下行更改为 False,那么您应该开始获取您期望的数据。

USE_TZ = False

【讨论】:

嗯....有趣。我会试试这个,看看会发生什么。我想我是处理时区的新手——我正在尝试根据时区等进行正确过滤,尽管我只将 UTC 用于实际的数据库记录。我一直在视图中进行时区计算。如果我这样处理,我不需要 USE_TZ 吗? 恐怕我还没有处理时区问题,我目前的项目也不需要,所以目前我的解决方案对我来说已经足够了。我希望这些信息已经为您提供了让您的代码再次运行所需的信息。【参考方案2】:

@Simon Wilder 完美回答了为什么它不起作用,这里是你如何在不禁用 django 中的 TZ 支持的情况下实际解决它

Django 文档给出instruction 将时区定义安装到数据库:

SQLite:安装 pytz — 转换实际上是在 Python 中执行的。

PostgreSQL:无要求(参见时区)。

Oracle:无要求(请参阅选择时区文件)。

mysql:安装pytz 并使用mysql_tzinfo_to_sql 加载时区表。

在我的例子中:mysql 和 Mac Os,下面的命令解决了这个问题:

sudo mysql_tzinfo_to_sql /usr/share/zoneinfo/ | mysql -u root mysql

【讨论】:

确实这应该是正确的答案。几乎每个项目都应该使用时区感知日期。【参考方案3】:

您的语法不正确。应该是:

Clicks.objects.filter(created__month=2)

(您离开了“对象”管理器)

【讨论】:

我想我没有指定 clicks 是我已经使用 .all() 或在 2014 年过滤的查询集,这似乎有效。 filter() 函数应该是一样的。在任何情况下,我都会更新问题以证明在创建查询集之前我得到了相同的结果。【参考方案4】:

因为我遇到了上述问题,所以在这里更新答案,但没有一个解决方案有效。大多数新的 mysql 安装都预装了 tz-info,因此 mysql_tzinfo_to_sql 命令不会真正有帮助。并且将 TZ_INFO 设置为 False 并不是真正的解决方案,因为许多人需要时区感知日期时间。

所以,对我有用的是创建一个 tz 感知日期时间对象并检查它。假设你想过滤今天的记录,你会做类似的事情,

from datetime import datetime
import pytz

today = datetime.now().replace(tzinfo=pytz.UTC).date()   # tz aware datetime object
todays_records = myModel.objects.filter(created__year=today.year, created__month=today.month,created__day=today.day)

希望这会有所帮助。

【讨论】:

以上是关于按月和日过滤 django 日期时间字段的问题的主要内容,如果未能解决你的问题,请参考以下文章

Drupal 视图 UI,过滤器暴露,集合字段内容中的日期仅按月和年(无天)

无论如何要更改日期输入字段中年、月和日分隔符 (/) 的占位符样式?

LINQ:在日期时间字段中按月和年分组

查看日期过滤器 - 粒度

从python中的第周、月和日获取日期

如何将年、月和日列合并到单个日期时间列?