Django& Postgresql将datetime字段注释到localtime

时间:2017-10-17 15:12:34

标签: django postgresql datetime timezone

我正在使用带有Postgresql 9.6和JQuery DataTables的Django 1.11(使用django-datatables从Djang模型提供AJax数据源。

模型示例:

class MyModel(models.Model):
    start = models.DateTimeField()
    end = = models.DateTimeField()

Postgresql以UTC时间信息存储日期时间,这很好。

我可以覆盖DataTables渲染列,以便在DataTables视图中正确呈现日期时间:

if column == "start":
    return timezone.localtime(row.start).strftime(STRFTIME_DATETIME_FORMAT)

尝试为部分日期提供搜索过滤器查询时出现的问题。如果我添加一个注释来添加date_str来搜索:

def filter_queryset(self, qs):
    search = self.request.GET.get(u'search[value]', None)
    if search:
        sql_datetime_format = getattr(settings, "SQL_DATETIME_FORMAT", "DD/MM/YYYY HH24:MI")
        qs = qs.annotate(
            start_str=Func(F('start'), Value(sql_datetime_format), function='to_char'),
            end_str=Func(F('end'), Value(sql_datetime_format), function='to_char'),
            )
        q_objects = Q()
        q_objects |= Q(start_str__icontains=search)
        q_objects |= Q(end_str__icontains=search)
        qs = qs.filter(q_objects).distinct()
    return qs

start_str和end_str将转换为字符串,作为UTC日期时间而不是本地日期时间。

所以我在夏天的英国日期正确显示为01/06/2017 00:00,但要搜索它,你必须输入:31/05/2017 23:00

我似乎无法找到将start_str和end_str转换为本地时间而不是UTC。

2 个答案:

答案 0 :(得分:1)

为了处理日期和时间,我最终为postgresql编写了自己的django表达式:

from django.db.models import Func

def ToChar(expression, output):
    '''
    Custom query to convert timestamp to string.

    Example usage
    queryset.annotate(
        created_date_str=ToChar('created_date', 'DD/MM/YYYY HH25:MI')
        )
    '''

    class ToCharWithoutTZ(Func):

        function = "TO_CHAR"
        template = '%(function)s(%(expressions)s, \'{output}\')'.format(output=output)

    return ToCharWithoutTZ(expression)

def ToCharTZ(expression, timezone, output):
    '''
    Custom query to convert timestamp to string in requested time zone.

    Example usage
    queryset.annotate(
        created_date_str=ToCharTZ('created_date', 'GB', 'DD/MM/YYYY HH25:MI')
        )
    '''

    class ToCharWithTZ(Func):

        function = "TO_CHAR"
        template = '%(function)s(%(expressions)s AT TIME ZONE \'{timezone}\', \'{output}\')'.format(timezone=timezone, output=output)

    return ToCharWithTZ(expression)

使用示例:

from myapp.models.functions import ToCharTZ

def filter_queryset(self, qs):
    search = self.request.GET.get(u'search[value]', None)
    if search:
        sql_datetime_format = getattr(settings, "SQL_DATETIME_FORMAT", "DD/MM/YYYY HH24:MI")
        qs = qs.annotate(
            start_str=ToCharTZ('start', 'GB', sql_datetime_format),
            end_str=ToCharTZ('end', 'GB', sql_datetime_format),
        )
    q_objects = Q()
    q_objects |= Q(start_str__icontains=search)
    q_objects |= Q(end_str__icontains=search)
    qs = qs.filter(q_objects).distinct()
    return qs

答案 1 :(得分:0)

在#django IRC频道的帮助下,我通过在django-pg-utils包中使用DateTZ解决了这个问题:

安装:

pip install django-pg-utils

更新了代码snippit:

from pg_utils.utils import DateTZ

def filter_queryset(self, qs):
    search = self.request.GET.get(u'search[value]', None)
    if search:
        sql_datetime_format = getattr(settings, "SQL_DATETIME_FORMAT", "DD/MM/YYYY HH24:MI")
        qs = qs.annotate(
            start_str=Func(DateTZ(F('start'), 'GB'), Value(sql_datetime_format), function='to_char'),
            end_str=Func(DateTZ(F('end'), 'GB'), Value(sql_datetime_format), function='to_char'),
        )
    q_objects = Q()
    q_objects |= Q(start_str__icontains=search)
    q_objects |= Q(end_str__icontains=search)
    qs = qs.filter(q_objects).distinct()
return qs

希望这对其他人有用。

相关问题