如何在覆盖的 Document.save 方法中处理可能的竞争条件 - Mongoengine

How to handle possible race-condition in overwritten Document.save method - Mongoengine

我正在使用 flask-mongoengine 并认为我 运行 在某种竞争条件下试图覆盖 Document.save 方法。

我的模型(简化版)如下所示:

class User(Document):
    meta = {"collection": "users"}
    name = StringField()


class Group(Document):
    meta = {"collection": "groups"}
    name = StringField()


class History(EmbeddedDocument):
    key = StringField()
    oldValue = StringField()
    newValue = StringField()


class Asset(DynamicDocument):
    meta = {"collection": "assets"}
    c_id = SequenceField()
    name = StringField()
    history = ListField(EmbeddedDocumentField(History))
    user = ReferenceField('User')
    group = ReferenceField('Group', required=True, default=Group.objects.first())

    def save(self, **kwargs):
        for key, value in self._data.items():
            history_update = History(
                key=key,
                oldValue="",
                newValue=str(value)
            )
            self.history.append(history_update)
        return super(Asset, self).save(**kwargs)

我想要实现的是:

创建 Asset 类型的新文档时,为每个 Key/Value 对更改的文档添加一个历史记录类型的条目。 (这里从 None 到一些 value,我在现有资产的更新方法中有类似的代码)。此历史列表应该类似于特定资产在其生命周期内的变更日志。

我当前实施的问题是:

  1. c_id 类型 SequenceField 在我的 for 循环中是 None
  2. str(value) 对于 User 对象给了我正确的用户对象(或者我的自定义 __str__ 方法的结果)但是 str(value) 对于 Group 对象给我 DBRef('groups', '<mongoidstring>') 并且不会触发我的客户 str 方法
  3. 事先使用断点进行调试时,不会出现这两个错误。 c_id 具有正确的值,我的 group 对象是一个组对象而不是 DBRef 对象

我之前尝试过保存文档一次,然后添加我的历史记录,这至少给了我一个正确的 c_id 但该组仍然是 DBRef.

我确实认为 SequenceField 是并行填充的,因此当我尝试访问它时仍然是 None,但当我通过调试器时却不是。但是 DBRef 仍然让我头疼。而且我真的没有看到通过覆盖保存方法来正确实现我的 ChangeHistory 的方法。任何想法如何正确处理这个?

所以我自己找到了答案(有点)。

  1. SequenceFields 仅在 save() 期间填充。当覆盖保存方法时,我们首先必须创建一个 super.save 来获取 SequenceField 值,或者我们必须通过 mongoengine 创建的助手集合来假定它的值。我采取了简单的方法,只是添加了一个 super(Asset, self).save() 并且 c_id 是为之后的更改而设置的。
  2. ReferenceFields 在您第一次从 Document 对象访问它之前可以用作 DBRef。 只需预先添加某种检查以确保正确解析其值,例如:
    assert self.group is not None
    assert self.user is not None