问题
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.
回答1:
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)
回答2:
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.
回答3:
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.
回答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)
回答5:
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
回答6:
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)
回答7:
Traditionally, I've set the creation_date
default to datetime.now()
and then have hidden the field on the admin form so you remove the possibility of a user overwriting the correct value. That requires almost no code.
Overriding the save method as suggested by Willian is also effective since you can programmtically block any updates to the creation_date
and update the modfied_date
at the same time.
回答8:
You could use auto_now_add parameter as per documentation:
class MyModel(mongoengine.Document):
creation_date = mongo.DateTimeField(auto_now_add = True)
modified_date = mongo.DateTimeField(auto_now = True)
来源:https://stackoverflow.com/questions/8098122/mongoengine-creation-time-attribute-in-document