2016-05-28 4 views
1

Mit einer Mongoengine Document, wenn ich eine DateTimeField von Mongo laden, fehlt es tzinfo. Unsere Anwendung nach Richtlinie möchte, dass alle Datumsangaben tzinfo haben.Wie kann ich CodecOptions auf eine Mongoengine-Sammlung anwenden, um TZinfo zu erhalten?

Wenn ich auf Mongo speichere, weiß ich, dass Pymongo die richtige und vorhersagbare Sache in Zeitzonen tut; Wenn es naiv ist, wird es als UTC-Zeit gespeichert, wenn es eine Zeitzone hat, wird es in UTC konvertiert und dann als UTC-Zeit gespeichert. Alles gut bis jetzt.

Wenn ich lade, aber DateTimeField gibt mir immer eine naive datetime. Ich weiß, dass datetime in UTC ist, also könnte ich die tzinfo hinzufügen, wenn ich wollte, aber ich würde dies an Dutzenden von Orten in meiner Anwendung tun müssen, und es ist eine Garantie für zukünftige Zeitzone Bugs , es sei denn ich benutze ein benutzerdefinierter Feldtyp (siehe Beispiel unten).

Referenzieren: https://api.mongodb.com/python/current/examples/datetimes.html Ich weiß, dass Pymongo unterstützt die tzinfo auf das Objekt, wie es aus der Datenbank ankommt. Ich weiß auch, dass ich das selbst machen kann, wie das folgende minimale Beispiel zeigt. Die DateTimeTZField fügt tzinfo in to_python hinzu.

from datetime import datetime 

from mongoengine import connect, Document, fields 

from pytz import timezone 

def utcnowTZ(): 
    return datetime.utcnow().replace(tzinfo=timezone('UTF')) 

class DateTimeTZField(fields.DateTimeField): 
    """ 
    This seems like a hack. I would like to use CodecOptions instead 
    """ 
    def to_python(self, value): 
     converted = super(DateTimeTZField, self).to_python(value) 
     return converted.replace(tzinfo=timezone('UTC')) 

class Thing(Document): 
    dtTZ = DateTimeTZField(default=utcnowTZ) 
    dtXX = fields.DateTimeField(default=utcnowTZ) 

connect(host="mongodb://localhost/datetimewithtz") 
Thing.objects().delete() 

t1 = Thing() 
print '%r.dtXX (default): %s' % (t1, t1.dtXX) 
print '%r.dtTZ (default): %s' % (t1, t1.dtTZ) 
t1.save() 
print 'saved %r' % t1.id; print 
t1 = Thing.objects(id=t1.id).first() 
print 'reloaded %r' % t1.id 
print '%r.dtXX (loaded): %s' % (t1, t1.dtXX) 
print '%r.dtTZ (loaded): %s' % (t1, t1.dtTZ) 

Ohne Datetimefield während meiner Anwendung zu ersetzen, ist es eine Möglichkeit, BSON CodecOptions verwenden auf diese global für alle DateTimeFields machen gelten: wenn aus der Datenbank geladen, sollten sie Tzinfo angeschlossen haben?

Antwort

1

Mein Verständnis ist, dass Mongoengine per-Modellcodec_options nicht unterstützt. Wenn dies der Fall ist, sollten sie Teil des opts Wörterbuchs here sein.

Allerdings verwendet PyMongo standardmäßig die codec_options der Datenbank, wenn die Sammlung keine eigene hat, und Sie können diese festlegen, indem Sie in Ihrer Anwendung manuell register_connection aufrufen, bevor Sie Anforderungen an die Datenbank stellen.

In Ihrem Beispiel oben sollten Sie die codec_options wie dies passieren:

with_timezone = CodecOptions() 
connect(host="mongodb://localhost/datetimewithtz", codec_options=with_timezone) 
+0

Danke für die nachdenkliche Antwort, ich komme wieder, sobald ich das versucht habe. Ich werde CodecOptions instanziieren (tz_aware = True), lassen Sie mich wissen, wenn das nicht stimmt. – Cory

Verwandte Themen