According to the Mongoengine API guide (http://mongoengine-odm.readthedocs.org/en/latest/apireference.html):
class mongoengine.queryset.QuerySet(document, collection)
is "a set of results returned from a query. Wraps a MongoDB cursor, providing Document objects as the results."
When I inspect the QuerySet object using type()
in my interpreter, it says that the QuerySet object is a <class 'mongoengine.queryset.QuerySet'>
, in agreement with the API guide.
I'm confused though because in order to actually access the individual Mongoengine Document
objects in the QuerySet instance, I have to use index methods like [0] (for the first Document
object) or [2] (for the third Document
object) See this SO question about slicing a QuerySet. Interestingly, you can also call len()
on a QuerySet instance.
Even though QuerySet is a class object, why does it seem to behave like a list object? As far as I can tell, it doesn't inherit from UserList
and doesn't have a data
attribute. Any help would be greatly appreciated.
Thanks.
EDIT:
Thanks for your suggestion @isbadawi. That is helpful. The QuerySet class object does indeed contain the __getitem__
method which, as your link suggests, is "roughly equivalent" to indexing (e.g. x.__getitem__(i)
is roughly equivalent to x[i]
). So if QuerySet is emulating a list class through __getitem__
, where are the actual Document
objects being stored in the class? In an attribute? This is the output of dir(QuerySet)
in my interpreter:
> ['_QuerySet__already_indexed', '_QuerySet__dereference', '__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__iter__', '__len__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_as_pymongo', '_as_pymongo_coerce', '_build_index_spec', '_class_check', '_collection', '_collection_obj', '_cursor', '_cursor_args', '_cursor_obj', '_dereference', '_document', '_ensure_indexes', '_fields_to_dbfields', '_get_as_pymongo', '_get_scalar', '_hint', '_initial_query', '_item_frequencies_exec_js', '_item_frequencies_map_reduce', '_iter', '_limit', '_loaded_fields', '_lookup_field', '_mongo_query', '_ordering', '_query', '_query_obj', '_reset_already_indexed', '_scalar', '_skip', '_slave_okay', '_snapshot', '_sub_js_fields', '_timeout', '_transform_query', '_transform_update', '_translate_field_name', '_where_clause', 'all', 'all_fields', 'as_pymongo', 'average', 'clone', 'count', 'create', 'delete', 'distinct', 'ensure_index', 'exclude', 'exec_js', 'explain', 'fields', 'filter', 'first', 'get', 'get_or_create', 'hint', 'in_bulk', 'insert', 'item_frequencies', 'limit', 'map_reduce', 'next', 'only', 'order_by', 'rewind', 'scalar', 'select_related', 'skip', 'slave_okay', 'snapshot', 'sum', 'timeout', 'update', 'update_one', 'values_list', 'where', 'with_id']
As seen in the code QuerySet
is a kind of abstraction over pymongo cursor
. Thus there is no storage inside QuerySet
.
When you call len()
QuerySet.__len__
magic method is called that returns the result of self.count()
that asks the count from the cursor.
And so on. QuerySet.__getitem__
asks the cursor for the corresponding item, QuerySet.first
do the same.
I strongly advise to look into the code when you in doubt how the things are implemented internally.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With