class EmbeddedDocumentForm( with_metaclass(DocumentFormMetaclass, BaseDocumentForm)): def __init__(self, parent_document, data=None, files=None, position=None, *args, **kwargs): if self._meta.embedded_field is not None and \ self._meta.embedded_field not in parent_document._fields: raise FieldError("Parent document must have field %s" % self._meta.embedded_field) instance = kwargs.pop('instance', None) if isinstance(parent_document._fields.get(self._meta.embedded_field), ListField): # if we received a list position of the instance and no instance # load the instance from the parent document and proceed as normal if instance is None and position is not None: instance = getattr(parent_document, self._meta.embedded_field)[position] # same as above only the other way around. Note: Mongoengine # defines equality as having the same data, so if you have 2 # objects with the same data the first one will be edited. That # may or may not be the right one. if instance is not None and position is None: emb_list = getattr(parent_document, self._meta.embedded_field) position = next( (i for i, obj in enumerate(emb_list) if obj == instance), None) super(EmbeddedDocumentForm, self).__init__(data=data, files=files, instance=instance, *args, **kwargs) self.parent_document = parent_document self.position = position def save(self, commit=True): """If commit is True the embedded document is added to the parent document. Otherwise the parent_document is left untouched and the embedded is returned as usual. """ if self.errors: raise ValueError("The %s could not be saved because the data" "didn't validate." % self.instance.__class__.__name__) if commit: field = self.parent_document._fields.get(self._meta.embedded_field) if isinstance(field, ListField) and self.position is None: # no position given, simply appending to ListField try: self.parent_document.update( ** {"push__" + self._meta.embedded_field: self.instance}) except: raise OperationError("The %s could not be appended." % self.instance.__class__.__name__) elif isinstance(field, ListField) and self.position is not None: # updating ListField at given position try: self.parent_document.update( **{ "__".join(("set", self._meta.embedded_field, str(self.position))): self.instance }) except: raise OperationError( "The %s could not be updated at " "position %d." % (self.instance.__class__.__name__, self.position)) else: # not a listfield on parent, treat as an embedded field setattr(self.parent_document, self._meta.embedded_field, self.instance) self.parent_document.save() return self.instance
class DocumentForm(with_metaclass(DocumentFormMetaclass, BaseDocumentForm)): pass