Source code for umongo.document

from .data_proxy import DataProxy
from .exceptions import NotCreatedError, AbstractDocumentError
from .meta import MetaDocument, DocumentOpts
from .data_objects import Reference
from .registerer import retrieve_document

from bson import DBRef


def _base_opts():
    opts = DocumentOpts('Document', {}, ())
    opts.abstract = True
    opts.allow_inheritance = True
    opts.register_document = False
    return opts


[docs]class Document(metaclass=MetaDocument): __slots__ = ('created', '_data', 'parent') # opts is generated by MetaDocument from Meta class except for root Document opts = _base_opts() def __init__(self, **kwargs): if self.opts.abstract: raise AbstractDocumentError("Cannot instantiate an abstract Document") super().__init__() self.created = False self._data = DataProxy(self.schema, data=kwargs if kwargs else None) def __repr__(self): return '<object Document %s.%s(%s)>' % ( self.__module__, self.__class__.__name__, self._data._data) def __eq__(self, other): if self.pk is None: return self is other elif isinstance(other, self.__class__) and other.pk is not None: return self.pk == other.pk elif isinstance(other, DBRef): return other.collection == self.collection.name and other.id == self.pk elif isinstance(other, Reference): return isinstance(self, other.document_cls) and self.pk == other.pk return NotImplemented @property def pk(self): """ Return the document's primary key (i.e. `_id` in mongo notation) or None if not available yet """ return self._data.get_by_mongo_name('_id') @property def dbref(self): """ Return a pymongo DBRef instance related to the document """ if not self.created: raise NotCreatedError('Must create the document before' ' having access to DBRef') return DBRef(collection=self.collection.name, id=self.pk) @classmethod
[docs] def build_from_mongo(cls, data, partial=False, use_cls=False): """ Create a document instance from MongoDB data :param data: data as retrieved from MongoDB :param use_cls: if the data contains a ``_cls`` field, use it determine the Document class to instanciate """ # If a _cls is specified, we have to use this document class if use_cls and '_cls' in data: cls = retrieve_document(data['_cls']) doc = cls() doc.from_mongo(data, partial=partial) return doc
[docs] def from_mongo(self, data, partial=False): """ Update the document with the MongoDB data :param data: data as retrieved from MongoDB """ # TODO: handle partial self._data.from_mongo(data, partial=partial) self.created = True
[docs] def to_mongo(self, update=False): """ """ if update and not self.created: raise NotCreatedError('Must create the document before' ' using update') return self._data.to_mongo(update=update)
[docs] def update(self, data, schema=None): """ Update the document with the given data :param schema: use this schema for the load instead of the default one """ return self._data.update(data, schema=schema)
[docs] def dump(self, schema=None): """ Dump the document: return a ``dict`` :param schema: use this schema for the dump instead of the default one """ return self._data.dump(schema=schema)
[docs] def clear_modified(self): """ Reset the list of document's modified items """ self._data.clear_modified()
@property def collection(self): """ Return the collection used by this Document class """ # Cannot implicitly access to the class's property return type(self).collection # Data-proxy accessor shortcuts def __getitem__(self, name): return self._data.get(name) def __delitem__(self, name): self._data.delete(name) def __setitem__(self, name, value): self._data.set(name, value) def __setattr__(self, name, value): if name in Document.__dict__: Document.__dict__[name].__set__(self, value) else: self._data.set(name, value, to_raise=AttributeError) def __getattr__(self, name): return self._data.get(name, to_raise=AttributeError) def __delattr__(self, name): self._data.delete(name, to_raise=AttributeError)