queryset_manager funcs now accept doc as arg
This commit is contained in:
parent
470e08f616
commit
2585f1b724
@ -44,7 +44,7 @@ are as follows:
|
||||
* :class:`~mongoengine.ReferenceField`
|
||||
|
||||
List fields
|
||||
^^^^^^^^^^^
|
||||
-----------
|
||||
MongoDB allows the storage of lists of items. To add a list of items to a
|
||||
:class:`~mongoengine.Document`, use the :class:`~mongoengine.ListField` field
|
||||
type. :class:`~mongoengine.ListField` takes another field object as its first
|
||||
@ -54,7 +54,7 @@ argument, which specifies which type elements may be stored within the list::
|
||||
tags = ListField(StringField(max_length=50))
|
||||
|
||||
Embedded documents
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
------------------
|
||||
MongoDB has the ability to embed documents within other documents. Schemata may
|
||||
be defined for these embedded documents, just as they may be for regular
|
||||
documents. To create an embedded document, just define a document as usual, but
|
||||
@ -76,7 +76,7 @@ document class as the first argument::
|
||||
page = Page(comments=[comment1, comment2])
|
||||
|
||||
Reference fields
|
||||
^^^^^^^^^^^^^^^^
|
||||
----------------
|
||||
References may be stored to other documents in the database using the
|
||||
:class:`~mongoengine.ReferenceField`. Pass in another document class as the
|
||||
first argument to the constructor, then simply assign document objects to the
|
||||
@ -100,7 +100,7 @@ The :class:`User` object is automatically turned into a reference behind the
|
||||
scenes, and dereferenced when the :class:`Page` object is retrieved.
|
||||
|
||||
Uniqueness constraints
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
----------------------
|
||||
MongoEngine allows you to specify that a field should be unique across a
|
||||
collection by providing ``unique=True`` to a :class:`~mongoengine.Field`\ 's
|
||||
constructor. If you try to save a document that has the same value for a unique
|
||||
@ -130,7 +130,7 @@ document class to use::
|
||||
meta = {'collection': 'cmsPage'}
|
||||
|
||||
Capped collections
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
------------------
|
||||
A :class:`~mongoengine.Document` may use a **Capped Collection** by specifying
|
||||
:attr:`max_documents` and :attr:`max_size` in the :attr:`meta` dictionary.
|
||||
:attr:`max_documents` is the maximum number of documents that is allowed to be
|
||||
@ -179,13 +179,13 @@ subsequent calls to :meth:`~mongoengine.queryset.QuerySet.order_by`. ::
|
||||
}
|
||||
|
||||
blog_post_1 = BlogPost(title="Blog Post #1")
|
||||
blog_post_1.published_date = datetime(2010, 1, 5, 0, 0 ,0))
|
||||
blog_post_1.published_date = datetime(2010, 1, 5, 0, 0 ,0)
|
||||
|
||||
blog_post_2 = BlogPost(title="Blog Post #2")
|
||||
blog_post_2.published_date = datetime(2010, 1, 6, 0, 0 ,0))
|
||||
blog_post_2.published_date = datetime(2010, 1, 6, 0, 0 ,0)
|
||||
|
||||
blog_post_3 = BlogPost(title="Blog Post #3")
|
||||
blog_post_3.published_date = datetime(2010, 1, 7, 0, 0 ,0))
|
||||
blog_post_3.published_date = datetime(2010, 1, 7, 0, 0 ,0)
|
||||
|
||||
blog_post_1.save()
|
||||
blog_post_2.save()
|
||||
@ -194,11 +194,11 @@ subsequent calls to :meth:`~mongoengine.queryset.QuerySet.order_by`. ::
|
||||
# get the "first" BlogPost using default ordering
|
||||
# from BlogPost.meta.ordering
|
||||
latest_post = BlogPost.objects.first()
|
||||
self.assertEqual(latest_post.title, "Blog Post #3")
|
||||
assert latest_post.title == "Blog Post #3"
|
||||
|
||||
# override default ordering, order BlogPosts by "published_date"
|
||||
first_post = BlogPost.objects.order_by("+published_date").first()
|
||||
self.assertEqual(first_post.title, "Blog Post #1")
|
||||
assert first_post.title == "Blog Post #1"
|
||||
|
||||
Document inheritance
|
||||
====================
|
||||
@ -218,7 +218,7 @@ convenient and efficient retrieval of related documents::
|
||||
date = DateTimeField()
|
||||
|
||||
Working with existing data
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
--------------------------
|
||||
To enable correct retrieval of documents involved in this kind of heirarchy,
|
||||
two extra attributes are stored on each document in the database: :attr:`_cls`
|
||||
and :attr:`_types`. These are hidden from the user through the MongoEngine
|
||||
|
@ -17,7 +17,7 @@ attribute syntax::
|
||||
'Example Page'
|
||||
|
||||
Saving and deleting documents
|
||||
-----------------------------
|
||||
=============================
|
||||
To save the document to the database, call the
|
||||
:meth:`~mongoengine.Document.save` method. If the document does not exist in
|
||||
the database, it will be created. If it does already exist, it will be
|
||||
@ -31,7 +31,7 @@ valide :attr:`id`.
|
||||
:ref:`guide-atomic-updates`
|
||||
|
||||
Document IDs
|
||||
------------
|
||||
============
|
||||
Each document in the database has a unique id. This may be accessed through the
|
||||
:attr:`id` attribute on :class:`~mongoengine.Document` objects. Usually, the id
|
||||
will be generated automatically by the database server when the object is save,
|
||||
|
@ -14,7 +14,7 @@ fetch documents from the database::
|
||||
print user.name
|
||||
|
||||
Filtering queries
|
||||
-----------------
|
||||
=================
|
||||
The query may be filtered by calling the
|
||||
:class:`~mongoengine.queryset.QuerySet` object with field lookup keyword
|
||||
arguments. The keys in the keyword arguments correspond to fields on the
|
||||
@ -33,7 +33,7 @@ syntax::
|
||||
uk_pages = Page.objects(author__country='uk')
|
||||
|
||||
Querying lists
|
||||
^^^^^^^^^^^^^^
|
||||
--------------
|
||||
On most fields, this syntax will look up documents where the field specified
|
||||
matches the given value exactly, but when the field refers to a
|
||||
:class:`~mongoengine.ListField`, a single item may be provided, in which case
|
||||
@ -47,7 +47,7 @@ lists that contain that item will be matched::
|
||||
Page.objects(tags='coding')
|
||||
|
||||
Query operators
|
||||
---------------
|
||||
===============
|
||||
Operators other than equality may also be used in queries; just attach the
|
||||
operator name to a key with a double-underscore::
|
||||
|
||||
@ -69,7 +69,7 @@ Available operators are as follows:
|
||||
* ``exists`` -- value for field exists
|
||||
|
||||
Limiting and skipping results
|
||||
-----------------------------
|
||||
=============================
|
||||
Just as with traditional ORMs, you may limit the number of results returned, or
|
||||
skip a number or results in you query.
|
||||
:meth:`~mongoengine.queryset.QuerySet.limit` and
|
||||
@ -86,15 +86,54 @@ achieving this is using array-slicing syntax::
|
||||
# 5 users, starting from the 10th user found
|
||||
users = User.objects[10:15]
|
||||
|
||||
Default Document queries
|
||||
========================
|
||||
By default, the objects :attr:`~mongoengine.Document.objects` attribute on a
|
||||
document returns a :class:`~mongoengine.queryset.QuerySet` that doesn't filter
|
||||
the collection -- it returns all objects. This may be changed by defining a
|
||||
method on a document that modifies a queryset. The method should accept two
|
||||
arguments -- :attr:`doc_cls` and :attr:`queryset`. The first argument is the
|
||||
:class:`~mongoengine.Document` class that the method is defined on (in this
|
||||
sense, the method is more like a :func:`classmethod` than a regular method),
|
||||
and the second argument is the initial queryset. The method needs to be
|
||||
decorated with :func:`~mongoengine.queryset.queryset_manager` in order for it
|
||||
to be recognised. ::
|
||||
|
||||
class BlogPost(Document):
|
||||
title = StringField()
|
||||
date = DateTimeField()
|
||||
|
||||
@queryset_manager
|
||||
def objects(doc_cls, queryset):
|
||||
# This may actually also be done by defining a default ordering for
|
||||
# the document, but this illustrates the use of manager methods
|
||||
return queryset.order_by('-date')
|
||||
|
||||
You don't need to call your method :attr:`objects` -- you may define as many
|
||||
custom manager methods as you like::
|
||||
|
||||
class BlogPost(Document):
|
||||
title = StringField()
|
||||
published = BooleanField()
|
||||
|
||||
@queryset_manager
|
||||
def live_posts(doc_cls, queryset):
|
||||
return queryset.order_by('-date')
|
||||
|
||||
BlogPost(title='test1', published=False).save()
|
||||
BlogPost(title='test2', published=True).save()
|
||||
assert len(BlogPost.objects) == 2
|
||||
assert len(BlogPost.live_posts) == 1
|
||||
|
||||
Aggregation
|
||||
-----------
|
||||
===========
|
||||
MongoDB provides some aggregation methods out of the box, but there are not as
|
||||
many as you typically get with an RDBMS. MongoEngine provides a wrapper around
|
||||
the built-in methods and provides some of its own, which are implemented as
|
||||
Javascript code that is executed on the database server.
|
||||
|
||||
Counting results
|
||||
^^^^^^^^^^^^^^^^
|
||||
----------------
|
||||
Just as with limiting and skipping results, there is a method on
|
||||
:class:`~mongoengine.queryset.QuerySet` objects --
|
||||
:meth:`~mongoengine.queryset.QuerySet.count`, but there is also a more Pythonic
|
||||
@ -103,7 +142,7 @@ way of achieving this::
|
||||
num_users = len(User.objects)
|
||||
|
||||
Further aggregation
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
-------------------
|
||||
You may sum over the values of a specific field on documents using
|
||||
:meth:`~mongoengine.queryset.QuerySet.sum`::
|
||||
|
||||
@ -133,7 +172,7 @@ would be generating "tag-clouds"::
|
||||
top_tags = sorted(tag_freqs.items(), key=itemgetter(1), reverse=True)[:10]
|
||||
|
||||
Advanced queries
|
||||
----------------
|
||||
================
|
||||
Sometimes calling a :class:`~mongoengine.queryset.QuerySet` object with keyword
|
||||
arguments can't fully express the query you want to use -- for example if you
|
||||
need to combine a number of constraints using *and* and *or*. This is made
|
||||
@ -161,7 +200,7 @@ calling it with keyword arguments::
|
||||
.. _guide-atomic-updates:
|
||||
|
||||
Atomic updates
|
||||
--------------
|
||||
==============
|
||||
Documents may be updated atomically by using the
|
||||
:meth:`~mongoengine.queryset.QuerySet.update_one` and
|
||||
:meth:`~mongoengine.queryset.QuerySet.update` methods on a
|
||||
|
@ -660,14 +660,15 @@ class QuerySetManager(object):
|
||||
# owner is the document that contains the QuerySetManager
|
||||
queryset = QuerySet(owner, self._collection)
|
||||
if self._manager_func:
|
||||
queryset = self._manager_func(queryset)
|
||||
queryset = self._manager_func(owner, queryset)
|
||||
return queryset
|
||||
|
||||
def queryset_manager(func):
|
||||
"""Decorator that allows you to define custom QuerySet managers on
|
||||
"""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.
|
||||
accepts a :class:`~mongoengine.Document` class as its first argument, and a
|
||||
:class:`~mongoengine.queryset.QuerySet` as its second argument. The method
|
||||
function should return a :class:`~mongoengine.queryset.QuerySet`, probably
|
||||
the same one that was passed in, but modified in some way.
|
||||
"""
|
||||
return QuerySetManager(func)
|
||||
|
@ -146,7 +146,7 @@ class QuerySetTest(unittest.TestCase):
|
||||
published_date = DateTimeField()
|
||||
|
||||
@queryset_manager
|
||||
def published(queryset):
|
||||
def published(doc_cls, queryset):
|
||||
return queryset(is_published=True)
|
||||
|
||||
blog_post_1 = BlogPost(title="Blog Post #1",
|
||||
@ -444,7 +444,7 @@ class QuerySetTest(unittest.TestCase):
|
||||
tags = ListField(StringField())
|
||||
|
||||
@queryset_manager
|
||||
def music_posts(queryset):
|
||||
def music_posts(doc_cls, queryset):
|
||||
return queryset(tags='music')
|
||||
|
||||
BlogPost.drop_collection()
|
||||
|
Loading…
x
Reference in New Issue
Block a user