Updates to documentation in prep for 0.5

This commit is contained in:
Ross Lawley 2011-09-09 05:45:56 -07:00
parent bc9a09f52e
commit a6449a7b2c
9 changed files with 240 additions and 155 deletions

View File

@ -4,14 +4,14 @@ Defining documents
In MongoDB, a **document** is roughly equivalent to a **row** in an RDBMS. When In MongoDB, a **document** is roughly equivalent to a **row** in an RDBMS. When
working with relational databases, rows are stored in **tables**, which have a working with relational databases, rows are stored in **tables**, which have a
strict **schema** that the rows follow. MongoDB stores documents in strict **schema** that the rows follow. MongoDB stores documents in
**collections** rather than tables - the principle difference is that no schema **collections** rather than tables - the principle difference is that no schema
is enforced at a database level. is enforced at a database level.
Defining a document's schema Defining a document's schema
============================ ============================
MongoEngine allows you to define schemata for documents as this helps to reduce MongoEngine allows you to define schemata for documents as this helps to reduce
coding errors, and allows for utility methods to be defined on fields which may coding errors, and allows for utility methods to be defined on fields which may
be present. be present.
To define a schema for a document, create a class that inherits from To define a schema for a document, create a class that inherits from
:class:`~mongoengine.Document`. Fields are specified by adding **field :class:`~mongoengine.Document`. Fields are specified by adding **field
@ -19,7 +19,7 @@ objects** as class attributes to the document class::
from mongoengine import * from mongoengine import *
import datetime import datetime
class Page(Document): class Page(Document):
title = StringField(max_length=200, required=True) title = StringField(max_length=200, required=True)
date_modified = DateTimeField(default=datetime.datetime.now) date_modified = DateTimeField(default=datetime.datetime.now)
@ -31,31 +31,34 @@ By default, fields are not required. To make a field mandatory, set the
validation constraints available (such as :attr:`max_length` in the example validation constraints available (such as :attr:`max_length` in the example
above). Fields may also take default values, which will be used if a value is above). Fields may also take default values, which will be used if a value is
not provided. Default values may optionally be a callable, which will be called not provided. Default values may optionally be a callable, which will be called
to retrieve the value (such as in the above example). The field types available to retrieve the value (such as in the above example). The field types available
are as follows: are as follows:
* :class:`~mongoengine.StringField` * :class:`~mongoengine.StringField`
* :class:`~mongoengine.URLField` * :class:`~mongoengine.URLField`
* :class:`~mongoengine.EmailField`
* :class:`~mongoengine.IntField` * :class:`~mongoengine.IntField`
* :class:`~mongoengine.FloatField` * :class:`~mongoengine.FloatField`
* :class:`~mongoengine.DecimalField` * :class:`~mongoengine.DecimalField`
* :class:`~mongoengine.DateTimeField` * :class:`~mongoengine.DateTimeField`
* :class:`~mongoengine.ComplexDateTimeField`
* :class:`~mongoengine.ListField` * :class:`~mongoengine.ListField`
* :class:`~mongoengine.SortedListField`
* :class:`~mongoengine.DictField` * :class:`~mongoengine.DictField`
* :class:`~mongoengine.MapField`
* :class:`~mongoengine.ObjectIdField` * :class:`~mongoengine.ObjectIdField`
* :class:`~mongoengine.EmbeddedDocumentField`
* :class:`~mongoengine.ReferenceField` * :class:`~mongoengine.ReferenceField`
* :class:`~mongoengine.GenericReferenceField` * :class:`~mongoengine.GenericReferenceField`
* :class:`~mongoengine.EmbeddedDocumentField`
* :class:`~mongoengine.BooleanField` * :class:`~mongoengine.BooleanField`
* :class:`~mongoengine.FileField` * :class:`~mongoengine.FileField`
* :class:`~mongoengine.EmailField`
* :class:`~mongoengine.SortedListField`
* :class:`~mongoengine.BinaryField` * :class:`~mongoengine.BinaryField`
* :class:`~mongoengine.GeoPointField` * :class:`~mongoengine.GeoPointField`
* :class:`~mongoengine.SequenceField`
Field arguments Field arguments
--------------- ---------------
Each field type can be customized by keyword arguments. The following keyword Each field type can be customized by keyword arguments. The following keyword
arguments can be set on all fields: arguments can be set on all fields:
:attr:`db_field` (Default: None) :attr:`db_field` (Default: None)
@ -74,7 +77,7 @@ arguments can be set on all fields:
The definion of default parameters follow `the general rules on Python The definion of default parameters follow `the general rules on Python
<http://docs.python.org/reference/compound_stmts.html#function-definitions>`__, <http://docs.python.org/reference/compound_stmts.html#function-definitions>`__,
which means that some care should be taken when dealing with default mutable objects which means that some care should be taken when dealing with default mutable objects
(like in :class:`~mongoengine.ListField` or :class:`~mongoengine.DictField`):: (like in :class:`~mongoengine.ListField` or :class:`~mongoengine.DictField`)::
class ExampleFirst(Document): class ExampleFirst(Document):
@ -89,7 +92,7 @@ arguments can be set on all fields:
# This can make an .append call to add values to the default (and all the following objects), # This can make an .append call to add values to the default (and all the following objects),
# instead to just an object # instead to just an object
values = ListField(IntField(), default=[1,2,3]) values = ListField(IntField(), default=[1,2,3])
:attr:`unique` (Default: False) :attr:`unique` (Default: False)
When True, no documents in the collection will have the same value for this When True, no documents in the collection will have the same value for this
@ -104,7 +107,13 @@ arguments can be set on all fields:
:attr:`choices` (Default: None) :attr:`choices` (Default: None)
An iterable of choices to which the value of this field should be limited. An iterable of choices to which the value of this field should be limited.
:attr:`help_text` (Default: None)
Optional help text to output with the field - used by form libraries
:attr:`verbose` (Default: None)
Optional human-readable name for the field - used by form libraries
List fields List fields
----------- -----------
@ -121,7 +130,7 @@ Embedded documents
MongoDB has the ability to embed documents within other documents. Schemata may 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 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 documents. To create an embedded document, just define a document as usual, but
inherit from :class:`~mongoengine.EmbeddedDocument` rather than inherit from :class:`~mongoengine.EmbeddedDocument` rather than
:class:`~mongoengine.Document`:: :class:`~mongoengine.Document`::
class Comment(EmbeddedDocument): class Comment(EmbeddedDocument):
@ -144,7 +153,7 @@ Often, an embedded document may be used instead of a dictionary -- generally
this is recommended as dictionaries don't support validation or custom field this is recommended as dictionaries don't support validation or custom field
types. However, sometimes you will not know the structure of what you want to types. However, sometimes you will not know the structure of what you want to
store; in this situation a :class:`~mongoengine.DictField` is appropriate:: store; in this situation a :class:`~mongoengine.DictField` is appropriate::
class SurveyResponse(Document): class SurveyResponse(Document):
date = DateTimeField() date = DateTimeField()
user = ReferenceField(User) user = ReferenceField(User)
@ -152,16 +161,19 @@ store; in this situation a :class:`~mongoengine.DictField` is appropriate::
survey_response = SurveyResponse(date=datetime.now(), user=request.user) survey_response = SurveyResponse(date=datetime.now(), user=request.user)
response_form = ResponseForm(request.POST) response_form = ResponseForm(request.POST)
survey_response.answers = response_form.cleaned_data() survey_response.answers = response_form.cleaned_data()
survey_response.save() survey_response.save()
Dictionaries can store complex data, other dictionaries, lists, references to
other objects, so are the most flexible field type available.
Reference fields Reference fields
---------------- ----------------
References may be stored to other documents in the database using the References may be stored to other documents in the database using the
:class:`~mongoengine.ReferenceField`. Pass in another document class as the :class:`~mongoengine.ReferenceField`. Pass in another document class as the
first argument to the constructor, then simply assign document objects to the first argument to the constructor, then simply assign document objects to the
field:: field::
class User(Document): class User(Document):
name = StringField() name = StringField()
@ -235,13 +247,13 @@ Its value can take any of the following constants:
in-memory, by the MongoEngine module, it is of the upmost importance in-memory, by the MongoEngine module, it is of the upmost importance
that the module that declares the relationship is loaded **BEFORE** the that the module that declares the relationship is loaded **BEFORE** the
delete is invoked. delete is invoked.
If, for example, the :class:`Employee` object lives in the If, for example, the :class:`Employee` object lives in the
:mod:`payroll` app, and the :class:`ProfilePage` in the :mod:`people` :mod:`payroll` app, and the :class:`ProfilePage` in the :mod:`people`
app, it is extremely important that the :mod:`people` app is loaded app, it is extremely important that the :mod:`people` app is loaded
before any employee is removed, because otherwise, MongoEngine could before any employee is removed, because otherwise, MongoEngine could
never know this relationship exists. never know this relationship exists.
In Django, be sure to put all apps that have such delete rule declarations in In Django, be sure to put all apps that have such delete rule declarations in
their :file:`models.py` in the :const:`INSTALLED_APPS` tuple. their :file:`models.py` in the :const:`INSTALLED_APPS` tuple.
@ -250,15 +262,15 @@ Generic reference fields
'''''''''''''''''''''''' ''''''''''''''''''''''''
A second kind of reference field also exists, A second kind of reference field also exists,
:class:`~mongoengine.GenericReferenceField`. This allows you to reference any :class:`~mongoengine.GenericReferenceField`. This allows you to reference any
kind of :class:`~mongoengine.Document`, and hence doesn't take a kind of :class:`~mongoengine.Document`, and hence doesn't take a
:class:`~mongoengine.Document` subclass as a constructor argument:: :class:`~mongoengine.Document` subclass as a constructor argument::
class Link(Document): class Link(Document):
url = StringField() url = StringField()
class Post(Document): class Post(Document):
title = StringField() title = StringField()
class Bookmark(Document): class Bookmark(Document):
bookmark_object = GenericReferenceField() bookmark_object = GenericReferenceField()
@ -272,9 +284,10 @@ kind of :class:`~mongoengine.Document`, and hence doesn't take a
Bookmark(bookmark_object=post).save() Bookmark(bookmark_object=post).save()
.. note:: .. note::
Using :class:`~mongoengine.GenericReferenceField`\ s is slightly less Using :class:`~mongoengine.GenericReferenceField`\ s is slightly less
efficient than the standard :class:`~mongoengine.ReferenceField`\ s, so if efficient than the standard :class:`~mongoengine.ReferenceField`\ s, so if
you will only be referencing one document type, prefer the standard you will only be referencing one document type, prefer the standard
:class:`~mongoengine.ReferenceField`. :class:`~mongoengine.ReferenceField`.
Uniqueness constraints Uniqueness constraints
@ -282,7 +295,7 @@ Uniqueness constraints
MongoEngine allows you to specify that a field should be unique across a MongoEngine allows you to specify that a field should be unique across a
collection by providing ``unique=True`` to a :class:`~mongoengine.Field`\ 's 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 constructor. If you try to save a document that has the same value for a unique
field as a document that is already in the database, a field as a document that is already in the database, a
:class:`~mongoengine.OperationError` will be raised. You may also specify :class:`~mongoengine.OperationError` will be raised. You may also specify
multi-field uniqueness constraints by using :attr:`unique_with`, which may be multi-field uniqueness constraints by using :attr:`unique_with`, which may be
either a single field name, or a list or tuple of field names:: either a single field name, or a list or tuple of field names::
@ -294,14 +307,14 @@ either a single field name, or a list or tuple of field names::
Skipping Document validation on save Skipping Document validation on save
------------------------------------ ------------------------------------
You can also skip the whole document validation process by setting You can also skip the whole document validation process by setting
``validate=False`` when caling the :meth:`~mongoengine.document.Document.save` ``validate=False`` when caling the :meth:`~mongoengine.document.Document.save`
method:: method::
class Recipient(Document): class Recipient(Document):
name = StringField() name = StringField()
email = EmailField() email = EmailField()
recipient = Recipient(name='admin', email='root@localhost') recipient = Recipient(name='admin', email='root@localhost')
recipient.save() # will raise a ValidationError while recipient.save() # will raise a ValidationError while
recipient.save(validate=False) # won't recipient.save(validate=False) # won't
@ -329,7 +342,7 @@ A :class:`~mongoengine.Document` may use a **Capped Collection** by specifying
stored in the collection, and :attr:`max_size` is the maximum size of the stored in the collection, and :attr:`max_size` is the maximum size of the
collection in bytes. If :attr:`max_size` is not specified and collection in bytes. If :attr:`max_size` is not specified and
:attr:`max_documents` is, :attr:`max_size` defaults to 10000000 bytes (10MB). :attr:`max_documents` is, :attr:`max_size` defaults to 10000000 bytes (10MB).
The following example shows a :class:`Log` document that will be limited to The following example shows a :class:`Log` document that will be limited to
1000 entries and 2MB of disk space:: 1000 entries and 2MB of disk space::
class Log(Document): class Log(Document):
@ -369,9 +382,10 @@ If a dictionary is passed then the following options are available:
Whether the index should be sparse. Whether the index should be sparse.
.. note:: .. note::
Geospatial indexes will be automatically created for all
Geospatial indexes will be automatically created for all
:class:`~mongoengine.GeoPointField`\ s :class:`~mongoengine.GeoPointField`\ s
Ordering Ordering
======== ========
A default ordering can be specified for your A default ordering can be specified for your
@ -393,7 +407,7 @@ subsequent calls to :meth:`~mongoengine.queryset.QuerySet.order_by`. ::
blog_post_1 = BlogPost(title="Blog Post #1") 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 = 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 = BlogPost(title="Blog Post #3")
@ -405,7 +419,7 @@ subsequent calls to :meth:`~mongoengine.queryset.QuerySet.order_by`. ::
# get the "first" BlogPost using default ordering # get the "first" BlogPost using default ordering
# from BlogPost.meta.ordering # from BlogPost.meta.ordering
latest_post = BlogPost.objects.first() latest_post = BlogPost.objects.first()
assert latest_post.title == "Blog Post #3" assert latest_post.title == "Blog Post #3"
# override default ordering, order BlogPosts by "published_date" # override default ordering, order BlogPosts by "published_date"
@ -434,7 +448,7 @@ Working with existing data
To enable correct retrieval of documents involved in this kind of heirarchy, 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` 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 and :attr:`_types`. These are hidden from the user through the MongoEngine
interface, but may not be present if you are trying to use MongoEngine with interface, but may not be present if you are trying to use MongoEngine with
an existing database. For this reason, you may disable this inheritance an existing database. For this reason, you may disable this inheritance
mechansim, removing the dependency of :attr:`_cls` and :attr:`_types`, enabling mechansim, removing the dependency of :attr:`_cls` and :attr:`_types`, enabling
you to work with existing databases. To disable inheritance on a document you to work with existing databases. To disable inheritance on a document

View File

@ -4,12 +4,12 @@ Documents instances
To create a new document object, create an instance of the relevant document To create a new document object, create an instance of the relevant document
class, providing values for its fields as its constructor keyword arguments. class, providing values for its fields as its constructor keyword arguments.
You may provide values for any of the fields on the document:: You may provide values for any of the fields on the document::
>>> page = Page(title="Test Page") >>> page = Page(title="Test Page")
>>> page.title >>> page.title
'Test Page' 'Test Page'
You may also assign values to the document's fields using standard object You may also assign values to the document's fields using standard object
attribute syntax:: attribute syntax::
>>> page.title = "Example Page" >>> page.title = "Example Page"
@ -18,9 +18,9 @@ attribute syntax::
Saving and deleting documents Saving and deleting documents
============================= =============================
MongoEngine tracks changes to documents to provide efficient saving. To save MongoEngine tracks changes to documents to provide efficient saving. To save
the document to the database, call the :meth:`~mongoengine.Document.save` method. 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 If the document does not exist in the database, it will be created. If it does
already exist, then any changes will be updated atomically. For example:: already exist, then any changes will be updated atomically. For example::
>>> page = Page(title="Test Page") >>> page = Page(title="Test Page")
@ -29,6 +29,7 @@ already exist, then any changes will be updated atomically. For example::
>>> page.save() # Performs an atomic set on the title field. >>> page.save() # Performs an atomic set on the title field.
.. note:: .. note::
Changes to documents are tracked and on the whole perform `set` operations. Changes to documents are tracked and on the whole perform `set` operations.
* ``list_field.pop(0)`` - *sets* the resulting list * ``list_field.pop(0)`` - *sets* the resulting list
@ -78,6 +79,7 @@ is an alias to :attr:`id`::
>>> page.id == page.pk >>> page.id == page.pk
.. note:: .. note::
If you define your own primary key field, the field implicitly becomes If you define your own primary key field, the field implicitly becomes
required, so a :class:`ValidationError` will be thrown if you don't provide required, so a :class:`ValidationError` will be thrown if you don't provide
it. it.

View File

@ -66,6 +66,7 @@ Deleting stored files is achieved with the :func:`delete` method::
marmot.photo.delete() marmot.photo.delete()
.. note:: .. note::
The FileField in a Document actually only stores the ID of a file in a The FileField in a Document actually only stores the ID of a file in a
separate GridFS collection. This means that deleting a document separate GridFS collection. This means that deleting a document
with a defined FileField does not actually delete the file. You must be with a defined FileField does not actually delete the file. You must be

View File

@ -1,31 +1,31 @@
====================== ======================
Installing MongoEngine Installing MongoEngine
====================== ======================
To use MongoEngine, you will need to download `MongoDB <http://mongodb.org/>`_ To use MongoEngine, you will need to download `MongoDB <http://mongodb.org/>`_
and ensure it is running in an accessible location. You will also need and ensure it is running in an accessible location. You will also need
`PyMongo <http://api.mongodb.org/python>`_ to use MongoEngine, but if you `PyMongo <http://api.mongodb.org/python>`_ to use MongoEngine, but if you
install MongoEngine using setuptools, then the dependencies will be handled for install MongoEngine using setuptools, then the dependencies will be handled for
you. you.
MongoEngine is available on PyPI, so to use it you can use MongoEngine is available on PyPI, so to use it you can use :program:`pip`:
:program:`easy_install`:
.. code-block:: console .. code-block:: console
# easy_install mongoengine $ pip install mongoengine
Alternatively, if you don't have setuptools installed, `download it from PyPi Alternatively, if you don't have setuptools installed, `download it from PyPi
<http://pypi.python.org/pypi/mongoengine/>`_ and run <http://pypi.python.org/pypi/mongoengine/>`_ and run
.. code-block:: console .. code-block:: console
# python setup.py install $ python setup.py install
To use the bleeding-edge version of MongoEngine, you can get the source from To use the bleeding-edge version of MongoEngine, you can get the source from
`GitHub <http://github.com/hmarr/mongoengine/>`_ and install it as above: `GitHub <http://github.com/hmarr/mongoengine/>`_ and install it as above:
.. code-block:: console .. code-block:: console
# git clone git://github.com/hmarr/mongoengine $ git clone git://github.com/hmarr/mongoengine
# cd mongoengine $ cd mongoengine
# python setup.py install $ python setup.py install

View File

@ -14,6 +14,7 @@ fetch documents from the database::
print user.name print user.name
.. note:: .. note::
Once the iteration finishes (when :class:`StopIteration` is raised), Once the iteration finishes (when :class:`StopIteration` is raised),
:meth:`~mongoengine.queryset.QuerySet.rewind` will be called so that the :meth:`~mongoengine.queryset.QuerySet.rewind` will be called so that the
:class:`~mongoengine.queryset.QuerySet` may be iterated over again. The :class:`~mongoengine.queryset.QuerySet` may be iterated over again. The
@ -39,29 +40,6 @@ syntax::
# been written by a user whose 'country' field is set to 'uk' # been written by a user whose 'country' field is set to 'uk'
uk_pages = Page.objects(author__country='uk') 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
lists that contain that item will be matched::
class Page(Document):
tags = ListField(StringField())
# This will match all pages that have the word 'coding' as an item in the
# 'tags' list
Page.objects(tags='coding')
Raw queries
-----------
It is possible to provide a raw PyMongo query as a query parameter, which will
be integrated directly into the query. This is done using the ``__raw__``
keyword argument::
Page.objects(__raw__={'tags': 'coding'})
.. versionadded:: 0.4
Query operators Query operators
=============== ===============
@ -99,26 +77,67 @@ expressions:
* ``endswith`` -- string field ends with value * ``endswith`` -- string field ends with value
* ``iendswith`` -- string field ends with value (case insensitive) * ``iendswith`` -- string field ends with value (case insensitive)
.. versionadded:: 0.3
There are a few special operators for performing geographical queries, that There are a few special operators for performing geographical queries, that
may used with :class:`~mongoengine.GeoPointField`\ s: may used with :class:`~mongoengine.GeoPointField`\ s:
* ``within_distance`` -- provide a list containing a point and a maximum * ``within_distance`` -- provide a list containing a point and a maximum
distance (e.g. [(41.342, -87.653), 5]) distance (e.g. [(41.342, -87.653), 5])
* ``within_spherical_distance`` -- Same as above but using the spherical geo model
(e.g. [(41.342, -87.653), 5/earth_radius])
* ``near`` -- order the documents by how close they are to a given point
* ``near_sphere`` -- Same as above but using the spherical geo model
* ``within_box`` -- filter documents to those within a given bounding box (e.g. * ``within_box`` -- filter documents to those within a given bounding box (e.g.
[(35.0, -125.0), (40.0, -100.0)]) [(35.0, -125.0), (40.0, -100.0)])
* ``near`` -- order the documents by how close they are to a given point * ``within_polygon`` -- filter documents to those within a given polygon (e.g.
[(41.91,-87.69), (41.92,-87.68), (41.91,-87.65), (41.89,-87.65)]).
.. note:: Requires Mongo Server 2.0
.. versionadded:: 0.4
Querying by position 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
lists that contain that item will be matched::
class Page(Document):
tags = ListField(StringField())
# This will match all pages that have the word 'coding' as an item in the
# 'tags' list
Page.objects(tags='coding')
It is possible to query by position in a list by using a numerical value as a It is possible to query by position in a list by using a numerical value as a
query operator. So if you wanted to find all pages whose first tag was ``db``, query operator. So if you wanted to find all pages whose first tag was ``db``,
you could use the following query:: you could use the following query::
BlogPost.objects(tags__0='db') Page.objects(tags__0='db')
If you only want to fetch part of a list eg: you want to paginate a list, then
the `slice` operator is required::
# comments - skip 5, limit 10
Page.objects.fields(slice__comments=[5, 10])
For updating documents, if you don't know the position in a list, you can use
the $ positional operator ::
Post.objects(comments__by="joe").update(**{'inc__comments__$__votes': 1})
However, this doesn't map well to the syntax so you can alos use a capital S instead ::
Post.objects(comments__by="joe").update(inc__comments__S__votes=1)
.. note:: Due to Mongo currently the $ operator only applies to the first matched item in the query.
Raw queries
-----------
It is possible to provide a raw PyMongo query as a query parameter, which will
be integrated directly into the query. This is done using the ``__raw__``
keyword argument::
Page.objects(__raw__={'tags': 'coding'})
.. versionadded:: 0.4 .. versionadded:: 0.4
@ -270,6 +289,7 @@ You may sum over the values of a specific field on documents using
yearly_expense = Employee.objects.sum('salary') yearly_expense = Employee.objects.sum('salary')
.. note:: .. note::
If the field isn't present on a document, that document will be ignored from If the field isn't present on a document, that document will be ignored from
the sum. the sum.
@ -318,6 +338,11 @@ will be given::
>>> f.rating # default value >>> f.rating # default value
3 3
.. note::
The :meth:`~mongoengine.queryset.QuerySet.exclude` is the opposite of
:meth:`~mongoengine.queryset.QuerySet.only` if you want to exclude a field.
If you later need the missing fields, just call If you later need the missing fields, just call
:meth:`~mongoengine.Document.reload` on your document. :meth:`~mongoengine.Document.reload` on your document.
@ -341,6 +366,67 @@ calling it with keyword arguments::
# Get top posts # Get top posts
Post.objects((Q(featured=True) & Q(hits__gte=1000)) | Q(hits__gte=5000)) Post.objects((Q(featured=True) & Q(hits__gte=1000)) | Q(hits__gte=5000))
.. _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
:meth:`~mongoengine.queryset.QuerySet`. There are several different "modifiers"
that you may use with these methods:
* ``set`` -- set a particular value
* ``unset`` -- delete a particular value (since MongoDB v1.3+)
* ``inc`` -- increment a value by a given amount
* ``dec`` -- decrement a value by a given amount
* ``pop`` -- remove the last item from a list
* ``push`` -- append a value to a list
* ``push_all`` -- append several values to a list
* ``pop`` -- remove the first or last element of a list
* ``pull`` -- remove a value from a list
* ``pull_all`` -- remove several values from a list
* ``add_to_set`` -- add value to a list only if its not in the list already
The syntax for atomic updates is similar to the querying syntax, but the
modifier comes before the field, not after it::
>>> post = BlogPost(title='Test', page_views=0, tags=['database'])
>>> post.save()
>>> BlogPost.objects(id=post.id).update_one(inc__page_views=1)
>>> post.reload() # the document has been changed, so we need to reload it
>>> post.page_views
1
>>> BlogPost.objects(id=post.id).update_one(set__title='Example Post')
>>> post.reload()
>>> post.title
'Example Post'
>>> BlogPost.objects(id=post.id).update_one(push__tags='nosql')
>>> post.reload()
>>> post.tags
['database', 'nosql']
.. note ::
In version 0.5 the :meth:`~mongoengine.Document.save` runs atomic updates
on changed documents by tracking changes to that document.
The positional operator allows you to update list items without knowing the
index position, therefore making the update a single atomic operation. As we
cannot use the `$` syntax in keyword arguments it has been mapped to `S`::
>>> post = BlogPost(title='Test', page_views=0, tags=['database', 'mongo'])
>>> post.save()
>>> BlogPost.objects(id=post.id, tags='mongo').update(set__tags__S='mongodb')
>>> post.reload()
>>> post.tags
['database', 'mongodb']
.. note ::
Currently only top level lists are handled, future versions of mongodb /
pymongo plan to support nested positional operators. See `The $ positional
operator <http://www.mongodb.org/display/DOCS/Updating#Updating-The%24positionaloperator>`_.
Server-side javascript execution Server-side javascript execution
================================ ================================
Javascript functions may be written and sent to the server for execution. The Javascript functions may be written and sent to the server for execution. The
@ -443,59 +529,3 @@ following example shows how the substitutions are made::
return comments; return comments;
} }
""") """)
.. _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
:meth:`~mongoengine.queryset.QuerySet`. There are several different "modifiers"
that you may use with these methods:
* ``set`` -- set a particular value
* ``unset`` -- delete a particular value (since MongoDB v1.3+)
* ``inc`` -- increment a value by a given amount
* ``dec`` -- decrement a value by a given amount
* ``pop`` -- remove the last item from a list
* ``push`` -- append a value to a list
* ``push_all`` -- append several values to a list
* ``pop`` -- remove the first or last element of a list
* ``pull`` -- remove a value from a list
* ``pull_all`` -- remove several values from a list
* ``add_to_set`` -- add value to a list only if its not in the list already
The syntax for atomic updates is similar to the querying syntax, but the
modifier comes before the field, not after it::
>>> post = BlogPost(title='Test', page_views=0, tags=['database'])
>>> post.save()
>>> BlogPost.objects(id=post.id).update_one(inc__page_views=1)
>>> post.reload() # the document has been changed, so we need to reload it
>>> post.page_views
1
>>> BlogPost.objects(id=post.id).update_one(set__title='Example Post')
>>> post.reload()
>>> post.title
'Example Post'
>>> BlogPost.objects(id=post.id).update_one(push__tags='nosql')
>>> post.reload()
>>> post.tags
['database', 'nosql']
The positional operator allows you to update list items without knowing the
index position, therefore making the update a single atomic operation. As we
cannot use the `$` syntax in keyword arguments it has been mapped to `S`::
>>> post = BlogPost(title='Test', page_views=0, tags=['database', 'mongo'])
>>> post.save()
>>> BlogPost.objects(id=post.id, tags='mongo').update(set__tags__S='mongodb')
>>> post.reload()
>>> post.tags
['database', 'mongodb']
.. note ::
Currently only top level lists are handled, future versions of mongodb /
pymongo plan to support nested positional operators. See `The $ positional
operator <http://www.mongodb.org/display/DOCS/Updating#Updating-The%24positionaloperator>`_.

View File

@ -41,9 +41,9 @@ Example usage::
logging.debug("Created") logging.debug("Created")
else: else:
logging.debug("Updated") logging.debug("Updated")
signals.pre_save.connect(Author.pre_save, sender=Author) signals.pre_save.connect(Author.pre_save, sender=Author)
signals.post_save.connect(Author.post_save, sender=Author) signals.post_save.connect(Author.post_save, sender=Author)
.. _blinker: http://pypi.python.org/pypi/blinker .. _blinker: http://pypi.python.org/pypi/blinker

View File

@ -2,35 +2,62 @@
MongoEngine User Documentation MongoEngine User Documentation
============================== ==============================
MongoEngine is an Object-Document Mapper, written in Python for working with **MongoEngine** is an Object-Document Mapper, written in Python for working with
MongoDB. To install it, simply run MongoDB. To install it, simply run
.. code-block:: console .. code-block:: console
# pip install -U mongoengine # pip install -U mongoengine
The source is available on `GitHub <http://github.com/hmarr/mongoengine>`_. :doc:`tutorial`
Start here for a quick overview.
:doc:`guide/index`
The Full guide to MongoEngine
:doc:`apireference`
The complete API documentation.
:doc:`django`
Using MongoEngine and Django
Community
---------
To get help with using MongoEngine, use the `MongoEngine Users mailing list To get help with using MongoEngine, use the `MongoEngine Users mailing list
<http://groups.google.com/group/mongoengine-users>`_ or come chat on the <http://groups.google.com/group/mongoengine-users>`_ or come chat on the
`#mongoengine IRC channel <irc://irc.freenode.net/mongoengine>`_. `#mongoengine IRC channel <irc://irc.freenode.net/mongoengine>`_.
If you are interested in contributing, join the developers' `mailing list Contributing
------------
The source is available on `GitHub <http://github.com/hmarr/mongoengine>`_ and
contributions are always encouraged. Contributions can be as simple as
minor tweaks to this documentation. To contribute, fork the project on
`GitHub <http://github.com/hmarr/mongoengine>`_ and send a
pull request.
Also, you can join the developers' `mailing list
<http://groups.google.com/group/mongoengine-dev>`_. <http://groups.google.com/group/mongoengine-dev>`_.
Changes
-------
See the :doc:`changelog` for a full list of changes to MongoEngine.
.. toctree:: .. toctree::
:maxdepth: 2 :hidden:
tutorial tutorial
guide/index guide/index
apireference apireference
django django
changelog changelog
upgrading upgrade
Indices and tables Indices and tables
================== ------------------
* :ref:`genindex` * :ref:`genindex`
* :ref:`modindex`
* :ref:`search` * :ref:`search`

View File

@ -5,24 +5,33 @@ Upgrading
0.4 to 0.5 0.4 to 0.5
=========== ===========
There have been the following backwards incompatibilities from 0.4 to 0.5: There have been the following backwards incompatibilities from 0.4 to 0.5. The
main areas of changed are: choices in fields, map_reduce and collection names.
# Choice options: Choice options:
--------------
Are now expected to be an iterable of tuples, with the first element in each Are now expected to be an iterable of tuples, with the first element in each
tuple being the actual value to be stored. The second element is the tuple being the actual value to be stored. The second element is the
human-readable name for the option. human-readable name for the option.
# PyMongo / MongoDB
map reduce now requires pymongo 1.11+ More methods now use map_reduce as db.eval PyMongo / MongoDB
is not supported for sharding - the following have been changed: -----------------
* sum map reduce now requires pymongo 1.11+- The pymongo merge_output and reduce_output
* average parameters, have been depreciated.
* item_frequencies
#. Default collection naming. More methods now use map_reduce as db.eval is not supported for sharding as such
the following have been changed:
* :meth:`~mongoengine.queryset.QuerySet.sum`
* :meth:`~mongoengine.queryset.QuerySet.average`
* :meth:`~mongoengine.queryset.QuerySet.item_frequencies`
Default collection naming
-------------------------
Previously it was just lowercase, its now much more pythonic and readable as its Previously it was just lowercase, its now much more pythonic and readable as its
lowercase and underscores, previously :: lowercase and underscores, previously ::

View File

@ -744,7 +744,7 @@ class QuerySet(object):
:param write_options: optional extra keyword arguments used if we :param write_options: optional extra keyword arguments used if we
have to create a new document. have to create a new document.
Passes any write_options onto :meth:`~mongoengine.document.Document.save` Passes any write_options onto :meth:`~mongoengine.Document.save`
.. versionadded:: 0.3 .. versionadded:: 0.3
""" """
@ -901,9 +901,11 @@ class QuerySet(object):
Returns an iterator yielding Returns an iterator yielding
:class:`~mongoengine.document.MapReduceDocument`. :class:`~mongoengine.document.MapReduceDocument`.
.. note:: Map/Reduce changed in server version **>= 1.7.4**. The PyMongo .. note::
:meth:`~pymongo.collection.Collection.map_reduce` helper requires
PyMongo version **>= 1.11**. Map/Reduce changed in server version **>= 1.7.4**. The PyMongo
:meth:`~pymongo.collection.Collection.map_reduce` helper requires
PyMongo version **>= 1.11**.
.. versionchanged:: 0.5 .. versionchanged:: 0.5
- removed ``keep_temp`` keyword argument, which was only relevant - removed ``keep_temp`` keyword argument, which was only relevant
@ -1070,8 +1072,7 @@ class QuerySet(object):
and `.exclude()` to manipulate which fields to retrieve. Fields also and `.exclude()` to manipulate which fields to retrieve. Fields also
allows for a greater level of control for example: allows for a greater level of control for example:
Retrieving a Subrange of Array Elements Retrieving a Subrange of Array Elements:
---------------------------------------
You can use the $slice operator to retrieve a subrange of elements in You can use the $slice operator to retrieve a subrange of elements in
an array :: an array ::
@ -1500,6 +1501,7 @@ class QuerySet(object):
This is useful for generating tag clouds, or searching documents. This is useful for generating tag clouds, or searching documents.
.. note:: .. note::
Can only do direct simple mappings and cannot map across Can only do direct simple mappings and cannot map across
:class:`~mongoengine.ReferenceField` or :class:`~mongoengine.ReferenceField` or
:class:`~mongoengine.GenericReferenceField` for more complex :class:`~mongoengine.GenericReferenceField` for more complex