Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoengine creation_time attribute in Document

I am trying to add a creation_time attribute to my documents. The following would be an example:

import datetime

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

Django models have built in parameter for their DateTimeField objects like add_now, etc., but MongoEngine does not support this.

I am wondering if best way to do this is the following:

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

or if there is a better, nicer way.

like image 506
josephmisiti Avatar asked Nov 11 '11 18:11

josephmisiti


7 Answers

You could override the save method.

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)
like image 135
Willian Avatar answered Sep 26 '22 20:09

Willian


As an aside, the creation time is stamped into the _id attribute - if you do:

YourObject.id.generation_time

Will give you a datetime stamp.

like image 31
Ben Hughes Avatar answered Sep 29 '22 20:09

Ben Hughes


One nice solution is reusing a single signal handler for multiple documents.

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)

Be careful to assign a callable and not a fixed-value as the default, for example default=datetime.utcnow without (). Some of the other answers on this page are incorrect and would cause created_at for new documents to always be set to the time your app was first loaded.

It's also always better to store UTC dates (datetime.utcnow instead of datetime.now) in your database.

like image 24
codebutler Avatar answered Sep 27 '22 20:09

codebutler


# -*- 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)
like image 39
allisson Avatar answered Sep 29 '22 20:09

allisson


My preferred solution is to use the @property decorator to return the creation datetime as extracted from the ObjectId:

@property
def creation_stamp(self):
    return self.id.generation_time
like image 35
Emanuel Ey Avatar answered Sep 26 '22 20:09

Emanuel Ey


Try use lambda value:

import datetime
from mongoengine import Document

class MyModel(Document):
    creation_date = mongo.DateTimeField()
    modified_date = mongo.DateTimeField(default=lambda : datetime.datetime.now())
like image 39
JohnDHH Avatar answered Sep 25 '22 20:09

JohnDHH


If you are using the timestamp field in a bunch of Documents you can keep your code DRY by creating an abstract Document instead.

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)
like image 43
Vikas Gulati Avatar answered Sep 29 '22 20:09

Vikas Gulati