From 84a8f1eb2b0c21f3e245469a469e14194c8c2d2a Mon Sep 17 00:00:00 2001 From: Hiroyasu OHYAMA Date: Tue, 28 Feb 2017 03:35:39 +0000 Subject: [PATCH] added OrderedDocument class to decode BSON data to OrderedDict for retrieving data in order --- mongoengine/document.py | 28 +++++++++++++++++++++++++++- mongoengine/queryset/base.py | 4 ++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/mongoengine/document.py b/mongoengine/document.py index b79e5e97..a2a5e156 100644 --- a/mongoengine/document.py +++ b/mongoengine/document.py @@ -1,6 +1,7 @@ import re import warnings +from collections import OrderedDict from bson.dbref import DBRef import pymongo from pymongo.read_preferences import ReadPreference @@ -21,7 +22,8 @@ from mongoengine.queryset import (NotUniqueError, OperationError, __all__ = ('Document', 'EmbeddedDocument', 'DynamicDocument', 'DynamicEmbeddedDocument', 'OperationError', - 'InvalidCollectionError', 'NotUniqueError', 'MapReduceDocument') + 'InvalidCollectionError', 'NotUniqueError', 'MapReduceDocument', + 'OrderedDocument') def includes_cls(fields): @@ -1036,3 +1038,27 @@ class MapReduceDocument(object): self._key_object = self._document.objects.with_id(self.key) return self._key_object return self._key_object + + +class OrderedDocument(Document): + """A document that is almost same with Document except for returning + results in OrderedDict instead of dict. + """ + + # The __metaclass__ attribute is removed by 2to3 when running with Python3 + # my_metaclass is defined so that metaclass can be queried in Python 2 & 3 + my_metaclass = TopLevelDocumentMetaclass + __metaclass__ = TopLevelDocumentMetaclass + + @classmethod + def _get_collection(cls): + collection = super(OrderedDocument, cls)._get_collection() + + if IS_PYMONGO_3: + # returns collection object which is set OrderedDict class to be decoded from BSON document + from bson import CodecOptions + return collection.with_options(codec_options=CodecOptions(document_class=OrderedDict)) + else: + # set attribute to specify the class to be decoeded + cls.decoded_class = OrderedDict + return collection diff --git a/mongoengine/queryset/base.py b/mongoengine/queryset/base.py index 7e485686..4738f5f7 100644 --- a/mongoengine/queryset/base.py +++ b/mongoengine/queryset/base.py @@ -1501,6 +1501,10 @@ class BaseQuerySet(object): cursor_args['read_preference'] = self._read_preference else: cursor_args['slave_okay'] = self._slave_okay + + # set decode format if needed + if hasattr(self._document, 'decoded_class'): + cursor_args['as_class'] = self._document.decoded_class else: fields_name = 'projection' # snapshot is not handled at all by PyMongo 3+