2017-10-17 22 views
0

J'utilise Django 1.11 avec Postgresql 9.6 et DataTables JQuery (en utilisant django-datatables pour fournir AJaX source de données du modèle DjangDjango & Postgresql annoter champ datetime à localtime

Modèle par exemple:.

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

. Postgresql stocke les datetimes UTC avec info fuseau horaire, ce qui est bien

Je peux passer outre les DataTables rendent la colonne de rendre correctement le datetime dans les DataTables Vue:

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

Problèmes lors de la tentative de fournir la requête de filtre de recherche pour des dates partielles. Si j'ajoute une annotation à ajouter DATE_STR à la recherche sur:

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 

Le start_str et end_str sont converties en chaînes comme UTC DateTimes pas datetimes locales.

Je UK date été affiche correctement comme 06.01.2017 00:00, mais pour le rechercher, vous devez entrer: 31/05/2017 23:00

Je ne peux pas sembler trouver loin pour obtenir start_str et end_str à l'heure locale au lieu de UTC.

Répondre

0

Pour faire face à la date et l'heure, je fini par écrire ma propre expression de django pour postgresql:

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) 

Exemple d'utilisation:

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 
0

Avec l'aide de #django canal IRC J'ai résolu ce problème en utilisant DateTZ dans le paquet-utils django-pg:

Pour installer:

pip install django-pg-utils 

code mis à jour 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 

Espérons que cela sera utile aux autres.

+0

Cela n'a pas retirer l'info fois, DateTZ seulement fonctionne avec la partie date, voir la réponse suivante. – Steve