关于django:Freezegun总是导致RuntimeWarning接收天真的日期时间

Freezegun always causes RuntimeWarning of receiving naive datetime

我正在处理一个可以挂起组织的测试用例。目前我用freezegun来冻结一个固定时间,这是datetime.datetime对象和tzinfo=pytz.UTC对象。

在下面的测试中,您将看到一个返回tzaware日期时间的self.fake_datetime的打印件:2000-01-01 00:00:00+00:00

当测试运行时,我不断得到著名的RuntimeWarning

/usr/local/lib/python2.7/dist-packages/django/db/models/fields/init.py:1447: RuntimeWarning: DateTimeField Organization.suspended received a naive datetime (2000-01-01 00:00:00) while time zone support is active.
RuntimeWarning)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import datetime
import pytz

from freezegun import freeze_time
# crop

class OrganizationSuspendTestCase(TestCase):

    def setUp(self):
        self.organization = OrganizationFactory()
        self.fake_datetime = datetime.datetime(2000, 1, 1, 0, 0, 0, tzinfo=pytz.UTC)
        print self.fake_datetime

    def test_suspend_organization(self):
       """
        Case: An organization is being suspended with the suspend service.
        Expected: The organization is updated with the suspending datetime and the reason.
       """
        with freeze_time(self.fake_datetime):
            mc_organization.services.organization.suspend(organization=self.organization, reason="Did not pay the bill")

        self.assertEqual(self.organization.suspended, datetime.datetime(2000, 1, 1, 0, 0, 0))

我一直在玩Freezegun时区示例,但没有成功删除运行时警告。

关于如何正确解决这个问题有什么建议吗?我想继续使用freezegun,不用RuntimeWarning。压制是一种选择,但我不喜欢。

更新——基于Xyres答案的解决方案

服务未意识到正在保存日期时间时区。旧情况注释,新情况是实际代码。我想了很多关于mocking的事情,并假设service中保存的日期时间将被freezegun从测试用例中模拟出的时区感知的日期时间对象,而事实并非如此。

1
2
3
4
5
6
7
8
9
10
11
def suspend(organization, reason):
   """
    Suspend an organization with the given reason.
    :param mc_organization.models.Organization organization: The organization to suspend.
    :param string reason: The reason of the suspending.
    :return: None
   """
    # organization.suspended = datetime.datetime.now() (Old sitation)
    organization.suspended = timezone.now()  # timezone aware situation.
    organization.suspended_reason = reason
    organization.save()


似乎您正试图用时区天真的日期时间保存对象。要消除此警告,只需在应用程序的任何位置使用时区感知的日期时间。

您可以使用django的timezone模块(位于django.utils.timezone上),而不是使用pytz手动管理时区。它有一些快捷方法,可以用来将naive datetime转换为aware datetime。

使用它的一个优点是,如果您更改了设置文件中的时区设置,它将自动选择新的时区,而使用pytz时,您必须在任何地方手动更新新的时区。

1
2
3
from django.utils import timezone

fake_datetime = timezone.make_aware(timezone.datetime(2000, 1, 1, 0, 0, 0))