Django 迁移中的自定义 sql 不起作用

Custom sql in django migration doesn't work

我正在尝试 运行 自定义 SQL 我的迁移。它是这样的:

from django.db import migrations

class Migration(migrations.Migration):

    dependencies = [
    ]

    operations = [
        migrations.RunSQL(
            "SET timezone TO 'UTC'",
        ),
    ]

当我 运行 它与

./manage.py migrate helper

我可以在日志中看到 SQL 命令是 运行:

[17/Feb/2017 20:37:37] DEBUG [django.db.backends.schema:103] SET timezone TO 'UTC'; (params None)
[17/Feb/2017 20:37:37] DEBUG [django.db.backends:90] (0.000) SET timezone TO 'UTC';

但是当我去数据库中检查它时,它仍然说时区是本地时间:

gdp=# show timezone;
 TimeZone  
-----------
 localtime
(1 row)

如果我 运行 手动执行相同的命令,它就可以正常工作:

gdp=# SET timezone TO 'UTC';
SET
gdp=# 
gdp=# show timezone;
 TimeZone 
----------
 UTC
(1 row)

Django 版本:1.10.5

PostgreSQL 版本:9.5.5

完整日志:

[17/Feb/2017 20:37:37] DEBUG [django.db.backends:90] (0.591) CREATE EXTENSION IF NOT EXISTS postgis; args=None
[17/Feb/2017 20:37:37] DEBUG [django.db.backends:90] (0.002) 
            SELECT c.relname, c.relkind
            FROM pg_catalog.pg_class c
            LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
            WHERE c.relkind IN ('r', 'v')
                AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
                AND pg_catalog.pg_table_is_visible(c.oid); args=None
[17/Feb/2017 20:37:37] DEBUG [django.db.backends.schema:103] CREATE TABLE "django_migrations" ("id" serial NOT NULL PRIMARY KEY, "app" varchar(255) NOT NULL, "name" varchar(255) NOT NULL, "applied" timestamp with time zone NOT NULL); (params None)
[17/Feb/2017 20:37:37] DEBUG [django.db.backends:90] (0.014) CREATE TABLE "django_migrations" ("id" serial NOT NULL PRIMARY KEY, "app" varchar(255) NOT NULL, "name" varchar(255) NOT NULL, "applied" timestamp with time zone NOT NULL); args=None
[17/Feb/2017 20:37:37] DEBUG [django.db.backends:90] (0.000) SELECT "django_migrations"."app", "django_migrations"."name" FROM "django_migrations"; args=()
[17/Feb/2017 20:37:37] DEBUG [django.db.backends:90] (0.001) 
            SELECT c.relname, c.relkind
            FROM pg_catalog.pg_class c
            LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
            WHERE c.relkind IN ('r', 'v')
                AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
                AND pg_catalog.pg_table_is_visible(c.oid); args=None
[17/Feb/2017 20:37:37] DEBUG [django.db.backends:90] (0.000) SELECT "django_migrations"."app", "django_migrations"."name" FROM "django_migrations"; args=()
[17/Feb/2017 20:37:37] DEBUG [django.db.backends.schema:103] SET timezone TO 'UTC'; (params None)
[17/Feb/2017 20:37:37] DEBUG [django.db.backends:90] (0.000) SET timezone TO 'UTC'; args=None
[17/Feb/2017 20:37:37] DEBUG [django.db.backends:90] (0.000) 
            SELECT c.relname, c.relkind
            FROM pg_catalog.pg_class c
            LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
            WHERE c.relkind IN ('r', 'v')
                AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
                AND pg_catalog.pg_table_is_visible(c.oid); args=None
[17/Feb/2017 20:37:37] DEBUG [django.db.backends:90] (0.000) INSERT INTO "django_migrations" ("app", "name", "applied") VALUES ('helper', '0001_initial', '2017-02-17T20:37:37.272476+00:00'::timestamptz) RETURNING "django_migrations"."id"; args=(u'helper', u'0001_initial', datetime.datetime(2017, 2, 17, 20, 37, 37, 272476, tzinfo=<UTC>))
[17/Feb/2017 20:37:37] DEBUG [django.db.backends:90] (0.001) 
            SELECT c.relname, c.relkind
            FROM pg_catalog.pg_class c
            LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
            WHERE c.relkind IN ('r', 'v')
                AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
                AND pg_catalog.pg_table_is_visible(c.oid); args=None
[17/Feb/2017 20:37:37] DEBUG [django.db.backends:90] (0.000) SELECT "django_migrations"."app", "django_migrations"."name" FROM "django_migrations"; args=()

编辑

我有这些设置:

USE_TZ = True 
TIME_ZONE = 'UTC' 

但是有了这个 Django 使用我的本地时区将日期时间保存到 Postgres,就像这样 '2016-09-12T08:06:45-04:00'。当我通过 Django 查询数据库时,它确实将它转换回 UTC,但我希望在 Postgres 中有 'clean' 日期时间,类似于这样的 '2016-09-12T12:06:45+00'.

当您使用 DateTimeField 时,Django 会设置自己的时区。在您的 settings.py 中,您应该找到此设置:

TIME_ZONE='UTC'

您可以通过将此设置为 None 来禁用 djangos timezone-usage。但是,我相信这只会将所有 DateTimeField-values 转换为没有时区的值。 (没试过)

我建议在任何情况下都使用 djangos TIME_ZONE 设置,因为它可以确保所有数据库的一致性。

我在 PostgreSQL 文档中找到了问题的答案 8.5.3. Time Zones:

The SQL command SET TIME ZONE sets the time zone for the session.

我可以通过在 postgresql.conf 中设置时区来解决这个问题(对我来说它位于 /etc/postgresql/9.5/主).