MongoEngine中为Document与EmbeddedDocument添加通用字段及方法报错求助
解决MongoEngine中Document和EmbeddedDocument复用时间戳字段的问题
你的问题根源在于Python2中旧式类的限制:SikkaBase没有继承object,属于旧式类,而MongoEngine的元类在处理多重继承时需要访问类的__class__属性,旧式类没有这个属性,所以抛出了AttributeError。另外,你写的save和update方法里的super调用逻辑也需要调整。
下面提供两种可行的解决方案:
方案一:修正Mixin类为新式类
把SikkaBase改成新式类(继承object),并修正方法中的super调用逻辑,确保正确触发MongoEngine基类的方法:
import datetime from mongoengine import Document, EmbeddedDocument, DateTimeField, BooleanField class SikkaBase(object): # 继承object成为新式类 created_on = DateTimeField(default=datetime.datetime.now) updated_on = DateTimeField(default=datetime.datetime.now) is_deleted = BooleanField(default=False) def save(self, *args, **kwargs): self.updated_on = datetime.datetime.now() # 根据继承链自动调用对应基类的save方法 return super(SikkaBase, self).save(*args, **kwargs) def update(self, *args, **kwargs): self.updated_on = datetime.datetime.now() # 注意:EmbeddedDocument本身没有update方法,该方法仅对Document子类生效 return super(SikkaBase, self).update(*args, **kwargs) class SikkaBaseDocument(Document, SikkaBase): meta = { 'abstract': True } class SikkaEmbeddedBaseDocument(EmbeddedDocument, SikkaBase): meta = { 'abstract': True }
方案二:使用MongoEngine信号(更优雅解耦)
MongoEngine提供了pre_save信号机制,可以在保存任何文档(包括嵌入式文档)之前自动更新时间戳,这种方式不需要依赖多重继承,代码更解耦:
import datetime from mongoengine import Document, EmbeddedDocument, DateTimeField, BooleanField from mongoengine.signals import pre_save def update_timestamp(sender, document, **kwargs): document.updated_on = datetime.datetime.now() # 仅对新创建的文档设置created_on(覆盖默认值逻辑) if not document.created_on: document.created_on = datetime.datetime.now() # 定义带通用字段的抽象基类 class TimestampedDocument(Document): created_on = DateTimeField() updated_on = DateTimeField() is_deleted = BooleanField(default=False) meta = { 'abstract': True } class TimestampedEmbeddedDocument(EmbeddedDocument): created_on = DateTimeField() updated_on = DateTimeField() is_deleted = BooleanField(default=False) meta = { 'abstract': True } # 给两个抽象基类注册信号,所有子类都会自动触发时间戳更新 pre_save.connect(update_timestamp, sender=TimestampedDocument) pre_save.connect(update_timestamp, sender=TimestampedEmbeddedDocument)
两种方案都能解决你的代码复用问题,方案二更符合MongoEngine的设计思路,也更灵活,推荐优先使用。
内容的提问来源于stack exchange,提问作者Varun Jain
相关产品推荐
相关产品推荐

