Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What exactly is the "QuerySet" object in Mongoengine?

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 Documentobject) 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']
like image 851
yuningalexliu Avatar asked Mar 01 '13 04:03

yuningalexliu


1 Answers

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.

like image 60
lig Avatar answered Oct 18 '22 20:10

lig