在MongoEngine中实现双向关系

23 投票
2 回答
5871 浏览
提问于 2025-04-16 05:10

我正在构建一个使用Django框架的应用,这个应用用MongoDB和MongoEngine来存储数据。为了简单说明我的问题,假设我想创建两个类:用户(User)和页面(Page)。每个页面都应该和一个用户关联,而每个用户也应该和一个页面关联。

from mongoengine import *

class Page(Document):
    pass

class User(Document):
    name = StringField()
    page = ReferenceField(Page)

class Page(Document):
    content = StringField()
    user = ReferenceField(User)

(注意,Page类必须在User类之前定义。如果我错过了处理循环依赖的Python方法,请告诉我。)每个文档可以正常创建和保存,但当我试图把一个页面分配给一个用户时,就会出现错误。

u = User(name='Jeff')
u.save()
p = Page(content="I'm a page!")
p.save()
p.user = u
p.save()
u.page = p
u.save()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "build\bdist.win32\egg\mongoengine\document.py", line 71, in save
  File "build\bdist.win32\egg\mongoengine\base.py", line 303, in validate
mongoengine.base.ValidationError: Invalid value for field of type "ReferenceField"

有没有人能解释一下为什么会出现这个异常,我哪里做错了,以及我该如何避免这个问题呢?

2 个回答

12

Drew的回答在这种情况下是最好的方法,但我想提一下,你也可以使用一个叫做GenereicReferenceField的东西:

from mongoengine import *

class User(Document):
    name = StringField()
    page = GenericReferenceField()

class Page(Document):
    content = StringField()
    user = ReferenceField(User)

不过,再说一次,针对你具体的问题,还是用单引号包裹类名比较好。

43

这是正确的解决方案:

from mongoengine import *

class User(Document):
    name = StringField()
    page = ReferenceField('Page')

class Page(Document):
    content = StringField()
    user = ReferenceField(User)

使用单引号('Page')来表示那些还没有定义的类。

撰写回答