Added queryset_manager decorator

This commit is contained in:
Harry Marr 2009-12-23 19:32:00 +00:00
parent 69eaf4b3f6
commit 3d70b65a45
7 changed files with 62 additions and 15 deletions

View File

@ -7,12 +7,12 @@ MongoEngine
About About
===== =====
MongoEngine is a Python Object-Document Mapper for working with MongoDB. MongoEngine is a Python Object-Document Mapper for working with MongoDB.
Documentation available at http://hmarr.com/mongoengine/ -- there is currently Documentation available at http://hmarr.com/mongoengine/ - there is currently
a `tutorial <http://hmarr.com/mongoengine/tutorial.html>`_, a `user guide a `tutorial <http://hmarr.com/mongoengine/tutorial.html>`_, a `user guide
<http://hmarr.com/mongoengine/userguide.html>`_ and an `API reference <http://hmarr.com/mongoengine/userguide.html>`_ and an `API reference
<http://hmarr.com/mongoengine/apireference.html>`_. <http://hmarr.com/mongoengine/apireference.html>`_.
Dependencies Dependencies
============ ============
pymongo 1.1+ - pymongo 1.1+
sphinx (optional -- for documentation generation) - sphinx (optional - for documentation generation)

View File

@ -27,6 +27,8 @@ Querying
.. autoclass:: mongoengine.queryset.QuerySet .. autoclass:: mongoengine.queryset.QuerySet
:members: :members:
.. autofunction:: mongoengine.queryset.queryset_manager
Fields Fields
====== ======

View File

@ -4,8 +4,11 @@ import fields
from fields import * from fields import *
import connection import connection
from connection import * from connection import *
import queryset
from queryset import *
__all__ = document.__all__ + fields.__all__ + connection.__all__ __all__ = (document.__all__ + fields.__all__ + connection.__all__ +
queryset.__all__)
__author__ = 'Harry Marr' __author__ = 'Harry Marr'

View File

@ -169,7 +169,7 @@ class TopLevelDocumentMetaclass(DocumentMetaclass):
# Set up collection manager, needs the class to have fields so use # Set up collection manager, needs the class to have fields so use
# DocumentMetaclass before instantiating CollectionManager object # DocumentMetaclass before instantiating CollectionManager object
new_class = super_new(cls, name, bases, attrs) new_class = super_new(cls, name, bases, attrs)
new_class.objects = QuerySetManager(new_class) new_class.objects = QuerySetManager()
return new_class return new_class

View File

@ -44,8 +44,8 @@ class Document(BaseDocument):
document already exists, it will be updated, otherwise it will be document already exists, it will be updated, otherwise it will be
created. created.
""" """
object_id = self.objects._collection.save(self.to_mongo()) object_id = self.__class__.objects._collection.save(self.to_mongo())
self.id = object_id self.id = self._fields['id'].to_python(object_id)
def delete(self): def delete(self):
"""Delete the :class:`~mongoengine.Document` from the database. This """Delete the :class:`~mongoengine.Document` from the database. This

View File

@ -3,6 +3,9 @@ from connection import _get_db
import pymongo import pymongo
__all__ = ['queryset_manager']
class QuerySet(object): class QuerySet(object):
"""A set of results returned from a query. Wraps a MongoDB cursor, """A set of results returned from a query. Wraps a MongoDB cursor,
providing :class:`~mongoengine.Document` objects as the results. providing :class:`~mongoengine.Document` objects as the results.
@ -182,12 +185,9 @@ class QuerySet(object):
class QuerySetManager(object): class QuerySetManager(object):
def __init__(self, document): def __init__(self, manager_func=None):
db = _get_db() self._manager_func = manager_func
self._document = document self._collection = None
self._collection_name = document._meta['collection']
# This will create the collection if it doesn't exist
self._collection = db[self._collection_name]
def __get__(self, instance, owner): def __get__(self, instance, owner):
"""Descriptor for instantiating a new QuerySet object when """Descriptor for instantiating a new QuerySet object when
@ -196,6 +196,22 @@ class QuerySetManager(object):
if instance is not None: if instance is not None:
# Document class being used rather than a document object # Document class being used rather than a document object
return self return self
if self._collection is None:
db = _get_db()
self._collection = db[owner._meta['collection']]
# self._document should be the same as owner # owner is the document that contains the QuerySetManager
return QuerySet(self._document, self._collection) queryset = QuerySet(owner, self._collection)
if self._manager_func:
queryset = self._manager_func(queryset)
return queryset
def queryset_manager(func):
"""Decorator that allows you to define custom QuerySet managers on
:class:`~mongoengine.Document` classes. The manager must be a function that
accepts a :class:`~mongoengine.queryset.QuerySet` as its only argument, and
returns a :class:`~mongoengine.queryset.QuerySet`, probably the same one
but modified in some way.
"""
return QuerySetManager(func)

View File

@ -214,6 +214,32 @@ class QuerySetTest(unittest.TestCase):
BlogPost.drop_collection() BlogPost.drop_collection()
def test_custom_manager(self):
"""Ensure that custom QuerySetManager instances work as expected.
"""
class BlogPost(Document):
tags = ListField(StringField())
@queryset_manager
def music_posts(queryset):
return queryset(tags='music')
BlogPost.drop_collection()
post1 = BlogPost(tags=['music', 'film'])
post1.save()
post2 = BlogPost(tags=['music'])
post2.save()
post3 = BlogPost(tags=['film', 'actors'])
post3.save()
self.assertEqual([p.id for p in BlogPost.objects],
[post1.id, post2.id, post3.id])
self.assertEqual([p.id for p in BlogPost.music_posts],
[post1.id, post2.id])
BlogPost.drop_collection()
def tearDown(self): def tearDown(self):
self.Person.drop_collection() self.Person.drop_collection()