2011-11-11 16 views
22

Sto tentando di aggiungere un attributo creation_time ai miei documenti. Di seguito sarebbe un esempio:Attributo di creazione_tempo Mongoengine nel documento

import datetime 

class MyModel(mongoengine.Document): 
    creation_date = mongo.DateTimeField() 
    modified_date = mongo.DateTimeField(default=datetime.datetime.now) 

modelli Django hanno costruito nel parametro per i loro oggetti come DateTimeFieldadd_now, ecc, ma MongoEngine non supporta questo.

Mi chiedo se il modo migliore per farlo è il seguente:

m,created = MyModel.objects.get_or_create() 
if created: 
    m.creation_date = datetime.datetime.now() 

o se c'è un modo migliore, più bello.

risposta

48

È possibile sovrascrivere il metodo di salvataggio.

class MyModel(mongoengine.Document): 
    creation_date = mongo.DateTimeField() 
    modified_date = mongo.DateTimeField(default=datetime.datetime.now) 

    def save(self, *args, **kwargs): 
     if not self.creation_date: 
      self.creation_date = datetime.datetime.now() 
     self.modified_date = datetime.datetime.now() 
     return super(MyModel, self).save(*args, **kwargs) 
+0

Questo è esattamente quello che mi serviva. Avevo capito il bit di default, ma l'override del metodo di salvataggio per tracciare il tempo modificato è perfetto. Grazie :) – Dawson

+0

Il problema con questo è che la funzione di salvataggio non verrà chiamata se si esegue un aggiornamento anziché a.risparmiare? – Nazariy1995

+0

@ Brenden1995 No, non funziona con l'aggiornamento. – Willian

-7

Si potrebbe utilizzare auto_now_add parametro come da documentation:

class MyModel(mongoengine.Document): 
    creation_date = mongo.DateTimeField(auto_now_add = True) 
    modified_date = mongo.DateTimeField(auto_now = True) 
+0

questi parametri non funzionano in mongoengine – josephmisiti

+1

Questo è il più sfortunato. Quindi sovrascrivere il salvataggio come nella risposta accettata è la risposta giusta. Vorrei creare una patch per aggiungere la funzionalità però :) –

+0

Questo non è un tizio di Django ... –

0

Tradizionalmente, ho impostato il creation_date predefinito per datetime.now() e poi hanno nascosto il campo nel modulo di amministrazione in modo da rimuovere la possibilità di un utente che sovrascrive il valore corretto. Ciò richiede quasi nessun codice.

L'override del metodo di salvataggio come suggerito da Willian è anche efficace poiché è possibile bloccare a livello di programmazione gli aggiornamenti allo creation_date e aggiornare lo modfied_date allo stesso tempo.

+1

quando dici "tradizionalmente", intendi l'uso specifico di Django ORM o MongoEngine? – josephmisiti

18

Per inciso, l'ora di creazione è impresso nel l'attributo _id - se si fa:

YourObject.id.generation_time 

vi darà un timbro datetime.

+0

Esattamente quello che stavo cercando, grazie. –

+2

Questo è migliore della risposta accettata. Ho usato '@ property' su una funzione come questa per ottenere il created_time:' def created_at (self): restituisce self.id.generation_time se self.id else None' – aaaronic

4
# -*- coding: utf-8 -*- 
from mongoengine import * 
from mongoengine import signals 
from datetime import datetime 

class User(Document): 
    email = StringField(required=True, unique=True) 
    first_name = StringField(max_length=50) 
    last_name = StringField(max_length=50) 
    # audit fields 
    created_on = DateTimeField(default=datetime.now()) 
    updated_on = DateTimeField(default=datetime.now()) 

    @classmethod 
    def pre_save(cls, sender, document, **kwargs): 
     document.updated_on = datetime.now() 

signals.pre_save.connect(User.pre_save, sender=User) 
4

Una bella soluzione sta riutilizzando un gestore di segnale singolo per più documenti.

class User(Document): 
    # other fields... 
    created_at = DateTimeField(required=True, default=datetime.utcnow) 
    updated_at = DateTimeField(required=True) 

class Post(Document): 
    # other fields... 
    created_at = DateTimeField(required=True, default=datetime.utcnow) 
    updated_at = DateTimeField(required=True) 

def update_timestamp(sender, document, **kwargs): 
    document.updated_at = datetime.utcnow() 

signals.pre_save.connect(update_timestamp, sender=User) 
signals.pre_save.connect(update_timestamp, sender=Post) 

Fare attenzione ad assegnare un callable e non un valore fisso come predefinito, ad esempio, senza default=datetime.utcnow(). Alcune delle altre risposte in questa pagina non sono corrette e causerebbero created_at per i nuovi documenti da impostare sempre al momento in cui l'app è stata caricata per la prima volta.

È anche sempre meglio memorizzare le date UTC (datetime.utcnow anziché datetime.now) nel database.

1

Se si utilizza il campo data/ora in un gruppo di documenti è possibile mantenere il codice DRY creando invece un documento astratto.

from datetime import datetime 
from mongoengine import Document 

class CreateUpdateDocument(Document): 
    meta = { 
     'abstract': True 
    } 

    # last updated timestamp 
    updated_at = DateTimeField(default=datetime.now) 

    # timestamp of when entry was created 
    created_at = DateTimeField(default=datetime.now) 

    def save(self, *args, **kwargs): 
     if not self.created_at: 
      self.created_at = datetime.now() 
     self.updated_at = datetime.now() 
     return super(CreateUpdateDocument, self).save(*args, **kwargs) 
+2

Si potrebbe voler mettere 'self.updated_at = datetime .now() 'sotto un'istruzione' else', quindi è possibile mantenere l'idea di "se update_at è none, significa che il modello non è mai stato aggiornato". – ldavid

3

La mia soluzione preferita è quella di utilizzare il @property decoratore di restituire il datetime creazione come estratto dal ObjectId:

@property 
def creation_stamp(self): 
    return self.id.generation_time 
Problemi correlati