文档中的 Mongoengine creation_time 属性

Posted

技术标签:

【中文标题】文档中的 Mongoengine creation_time 属性【英文标题】:Mongoengine creation_time attribute in Document 【发布时间】:2011-11-11 18:07:51 【问题描述】:

我正在尝试将creation_time 属性添加到我的文档中。下面是一个例子:

import datetime

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

Django 模型为其DateTimeField 对象(如add_now 等)内置了参数, 但是 MongoEngine 不支持这个。

我想知道最好的方法是否如下:

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

或者如果有更好更好的方法。

【问题讨论】:

【参考方案1】:

您可以覆盖保存方法。

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)

【讨论】:

这正是我所需要的。我已经找到了默认位,但是覆盖 save 方法来跟踪修改时间是完美的。谢谢你:) 这个问题是如果你更新而不是 .save 就不会调用 save 函数吗? 覆盖clean方法而不是save应该更好,docs here 使用函数update时无法更新modified_date【参考方案2】:

顺便说一句,创建时间被标记到 _id 属性中 - 如果你这样做:

YourObject.id.generation_time

会给你一个日期时间戳

【讨论】:

这比接受的答案要好。我在这样的函数上使用了@property 来获取created_time:def created_at(self): return self.id.generation_time if self.id else None【参考方案3】:

一个不错的解决方案是为多个文档重用一个信号处理程序。

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)

注意将可调用而不是固定值指定为默认值,例如 default=datetime.utcnow 没有 ()。此页面上的其他一些答案不正确,会导致 created_at 始终将新文档设置为您的应用首次加载的时间。

在您的数据库中存储 UTC 日期(datetime.utcnow 而不是 datetime.now)总是更好。

【讨论】:

【参考方案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】:

我首选的解决方案是使用 @property 装饰器返回从 ObjectId 中提取的创建日期时间:

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

【讨论】:

【参考方案6】:

如果您在一堆文档中使用时间戳字段,您可以通过创建一个抽象文档来保留您的代码DRY。

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)

【讨论】:

您可能希望将self.updated_at = datetime.now() 放在else 语句下,这样您就可以保持“如果updated_at 为none,则意味着模型从未更新”的想法。【参考方案7】:

尝试使用 lambda 值:

import datetime
from mongoengine import Document

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

【讨论】:

不需要使用 lambda,只需使用 mongo.DateTimeField(default=datetime.datetime.now)【参考方案8】:

传统上,我将creation_date 默认设置为datetime.now(),然后在管理表单上隐藏了该字段,这样您就可以消除用户覆盖正确值的可能性。这几乎不需要任何代码。

按照 Willian 的建议覆盖 save 方法也很有效,因为您可以通过编程方式阻止对 creation_date 的任何更新并同时更新 modfied_date

【讨论】:

当您说“传统”时,您是指专门使用 Django ORM 还是 MongoEngine?【参考方案9】:

您可以按照documentation 使用 auto_now_add 参数:

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

【讨论】:

那是最不幸的。然后在接受的答案中覆盖保存是正确的答案。我会创建一个补丁来添加该功能:)

以上是关于文档中的 Mongoengine creation_time 属性的主要内容,如果未能解决你的问题,请参考以下文章

使用 mongoengine 将多文档插入到 mongodb

Python Mongoengine:如何绕过无法通过验证的文档以避免崩溃

MongoEngine 的嵌入式文档问题

带有 DataFrames 的 Mongoengine 文档

使用 mongoengine 编写一个空的 dict 字段

mongoengine