如何使用 flask mongoengine 处理 ReferenceField 迁移?

How to handle ReferenceField migration with flask mongoengine?

我已经使用 mongodb 实现了一个简单的 flask 应用程序,现在需要一些升级。

假设 Foo 有一个 class 模型,Bar 有一个 class 模型,其中有一个 Foo

的引用字段
class Foo(Document):
  title = StringField()

class Bar(Document):
  name = StringField()
  foo = ReferenceField('Foo')

让 flask 应用程序运行一段时间,以便数据库中现在有一些数据。

由于需求变化,我们需要重构 Foo class subclassing 从一个新的 super class:

class SuperFoo(Document):
  meta = { 'allow_inheritance': True,}
  #[...]

class Foo(SuperFoo):
  #[...]

class Bar(Document):
  name = StringField()
  foo = ReferenceField('Foo')

上面的代码适用于空数据库。

但是如果其中有一些数据,当 flask 管理员试图显示 Bar 实例(在编辑模式下)时,mongoengine 会引发异常

File "[...]/site-packages/mongoengine/fields.py", line 1124, in __get__
    raise DoesNotExist('Trying to dereference unknown document %s' % value)
mongoengine.errors.DoesNotExist: Trying to dereference unknown document DBRef('super_foo', ObjectId('5617a08939c6c70cbaa2af6e'))

我想数据模型需要以某种方式迁移。

如何?

谢谢, 亚历山德罗

经过一番分析,我想出了解决问题的方法。

Mongoengine 创建一个新集合 super_foo

每个继承 class 的文档都进入这个 super_foo 集合,并带有附加属性 _cls。 该值是 class 的 CamelCased 层次结构路径。在此示例中,文档将具有

'_cls': 'SuperFoo.Foo' 字段。

我所做的是将旧 foo 集合中的每个文档复制到新 super_foo 集合中,并向每个文档添加字段 {'_cls': u'SuperPlesso.Plesso'}

迁移函数应该如下所示:

def migrationFunc():
    from pymongo.errors import DuplicateKeyError
    from my.app import models

    _cls = {'_cls': u'SuperFoo.Foo'}

    fromOldCollection = models.Foo._collection
    toSuperCollection = models.Superfoo._collection

    for doc in fromOldCollection.find():
        doc.update(_cls)
        try:
            toSuperCollection.insert(doc)
        except DuplicateKeyError:
            logger.error('...')

然后我用实际的新层次结构更新了模型的基本代码:

class SuperFoo(Document):
  meta = { 'allow_inheritance': True,}
  #[...]

# was class Foo(Document)
class Foo(SuperFoo):
  #[...]

Bar 集合或其他地方对 Foo 的所有反向引用都被保留。