Skip to content

Commit 39e2773

Browse files
committed
Merge branch 'v0.4' of git://github.com/hmarr/mongoengine into v0.4
Conflicts: docs/changelog.rst mongoengine/base.py mongoengine/queryset.py
2 parents dc7181a + 0902b95 commit 39e2773

13 files changed

+707
-231
lines changed

docs/apireference.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,5 @@ Fields
6666
.. autoclass:: mongoengine.GenericReferenceField
6767

6868
.. autoclass:: mongoengine.FileField
69+
70+
.. autoclass:: mongoengine.GeoPointField

docs/changelog.rst

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,26 @@ Changes in v0.4
66
===============
77
- Added ``GridFSStorage`` Django storage backend
88
- Added ``FileField`` for GridFS support
9+
- New Q-object implementation, which is no longer based on Javascript
910
- Added ``SortedListField``
1011
- Added ``EmailField``
1112
- Added ``GeoPointField``
1213
- Added ``exact`` and ``iexact`` match operators to ``QuerySet``
1314
- Added ``get_document_or_404`` and ``get_list_or_404`` Django shortcuts
14-
- Fixed bug in Q-objects
15+
- Added new query operators for Geo queries
16+
- Added ``not`` query operator
17+
- Added new update operators: ``pop`` and ``add_to_set``
18+
- Added ``__raw__`` query parameter
19+
- Added support for custom querysets
1520
- Fixed document inheritance primary key issue
21+
- Added support for querying by array element position
1622
- Base class can now be defined for ``DictField``
1723
- Fixed MRO error that occured on document inheritance
24+
- Added ``QuerySet.distinct``, ``QuerySet.create``, ``QuerySet.snapshot``,
25+
``QuerySet.timeout`` and ``QuerySet.all``
26+
- Subsequent calls to ``connect()`` now work
1827
- Introduced ``min_length`` for ``StringField``
28+
- Fixed multi-process connection issue
1929
- Other minor fixes
2030

2131
Changes in v0.3

docs/guide/defining-documents.rst

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ are as follows:
4747
* :class:`~mongoengine.ReferenceField`
4848
* :class:`~mongoengine.GenericReferenceField`
4949
* :class:`~mongoengine.BooleanField`
50-
* :class:`~mongoengine.GeoLocationField`
5150
* :class:`~mongoengine.FileField`
5251
* :class:`~mongoengine.EmailField`
5352
* :class:`~mongoengine.SortedListField`
5453
* :class:`~mongoengine.BinaryField`
54+
* :class:`~mongoengine.GeoPointField`
5555

5656
Field arguments
5757
---------------
@@ -72,6 +72,25 @@ arguments can be set on all fields:
7272
:attr:`default` (Default: None)
7373
A value to use when no value is set for this field.
7474

75+
The definion of default parameters follow `the general rules on Python
76+
<http://docs.python.org/reference/compound_stmts.html#function-definitions>`__,
77+
which means that some care should be taken when dealing with default mutable objects
78+
(like in :class:`~mongoengine.ListField` or :class:`~mongoengine.DictField`)::
79+
80+
class ExampleFirst(Document):
81+
# Default an empty list
82+
values = ListField(IntField(), default=list)
83+
84+
class ExampleSecond(Document):
85+
# Default a set of values
86+
values = ListField(IntField(), default=lambda: [1,2,3])
87+
88+
class ExampleDangerous(Document):
89+
# This can make an .append call to add values to the default (and all the following objects),
90+
# instead to just an object
91+
values = ListField(IntField(), default=[1,2,3])
92+
93+
7594
:attr:`unique` (Default: False)
7695
When True, no documents in the collection will have the same value for this
7796
field.
@@ -279,6 +298,10 @@ or a **-** sign. Note that direction only matters on multi-field indexes. ::
279298
meta = {
280299
'indexes': ['title', ('title', '-rating')]
281300
}
301+
302+
.. note::
303+
Geospatial indexes will be automatically created for all
304+
:class:`~mongoengine.GeoPointField`\ s
282305

283306
Ordering
284307
========

docs/guide/querying.rst

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ lists that contain that item will be matched::
5353
# 'tags' list
5454
Page.objects(tags='coding')
5555

56+
Raw queries
57+
-----------
58+
It is possible to provide a raw PyMongo query as a query parameter, which will
59+
be integrated directly into the query. This is done using the ``__raw__``
60+
keyword argument::
61+
62+
Page.objects(__raw__={'tags': 'coding'})
63+
64+
.. versionadded:: 0.4
65+
5666
Query operators
5767
===============
5868
Operators other than equality may also be used in queries; just attach the
@@ -68,6 +78,8 @@ Available operators are as follows:
6878
* ``lte`` -- less than or equal to
6979
* ``gt`` -- greater than
7080
* ``gte`` -- greater than or equal to
81+
* ``not`` -- negate a standard check, may be used before other operators (e.g.
82+
``Q(age__not__mod=5)``)
7183
* ``in`` -- value is in list (a list of values should be provided)
7284
* ``nin`` -- value is not in list (a list of values should be provided)
7385
* ``mod`` -- ``value % x == y``, where ``x`` and ``y`` are two provided values
@@ -89,6 +101,27 @@ expressions:
89101

90102
.. versionadded:: 0.3
91103

104+
There are a few special operators for performing geographical queries, that
105+
may used with :class:`~mongoengine.GeoPointField`\ s:
106+
107+
* ``within_distance`` -- provide a list containing a point and a maximum
108+
distance (e.g. [(41.342, -87.653), 5])
109+
* ``within_box`` -- filter documents to those within a given bounding box (e.g.
110+
[(35.0, -125.0), (40.0, -100.0)])
111+
* ``near`` -- order the documents by how close they are to a given point
112+
113+
.. versionadded:: 0.4
114+
115+
Querying by position
116+
====================
117+
It is possible to query by position in a list by using a numerical value as a
118+
query operator. So if you wanted to find all pages whose first tag was ``db``,
119+
you could use the following query::
120+
121+
BlogPost.objects(tags__0='db')
122+
123+
.. versionadded:: 0.4
124+
92125
Limiting and skipping results
93126
=============================
94127
Just as with traditional ORMs, you may limit the number of results returned, or
@@ -181,6 +214,22 @@ custom manager methods as you like::
181214
assert len(BlogPost.objects) == 2
182215
assert len(BlogPost.live_posts) == 1
183216

217+
Custom QuerySets
218+
================
219+
Should you want to add custom methods for interacting with or filtering
220+
documents, extending the :class:`~mongoengine.queryset.QuerySet` class may be
221+
the way to go. To use a custom :class:`~mongoengine.queryset.QuerySet` class on
222+
a document, set ``queryset_class`` to the custom class in a
223+
:class:`~mongoengine.Document`\ s ``meta`` dictionary::
224+
225+
class AwesomerQuerySet(QuerySet):
226+
pass
227+
228+
class Page(Document):
229+
meta = {'queryset_class': AwesomerQuerySet}
230+
231+
.. versionadded:: 0.4
232+
184233
Aggregation
185234
===========
186235
MongoDB provides some aggregation methods out of the box, but there are not as
@@ -402,8 +451,10 @@ that you may use with these methods:
402451
* ``pop`` -- remove the last item from a list
403452
* ``push`` -- append a value to a list
404453
* ``push_all`` -- append several values to a list
454+
* ``pop`` -- remove the first or last element of a list
405455
* ``pull`` -- remove a value from a list
406456
* ``pull_all`` -- remove several values from a list
457+
* ``add_to_set`` -- add value to a list only if its not in the list already
407458

408459
The syntax for atomic updates is similar to the querying syntax, but the
409460
modifier comes before the field, not after it::

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ MongoDB. To install it, simply run
77

88
.. code-block:: console
99
10-
# easy_install -U mongoengine
10+
# pip install -U mongoengine
1111
1212
The source is available on `GitHub <http://github.com/hmarr/mongoengine>`_.
1313

mongoengine/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
__author__ = 'Harry Marr'
1414

15-
VERSION = (0, 3, 0)
15+
VERSION = (0, 4, 0)
1616

1717
def get_version():
1818
version = '%s.%s' % (VERSION[0], VERSION[1])

mongoengine/base.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import sys
55
import pymongo
6+
import pymongo.objectid
67

78

89
_document_registry = {}
@@ -203,6 +204,9 @@ def __new__(cls, name, bases, attrs):
203204
exc = subclass_exception('MultipleObjectsReturned', base_excs, module)
204205
new_class.add_to_class('MultipleObjectsReturned', exc)
205206

207+
global _document_registry
208+
_document_registry[name] = new_class
209+
206210
return new_class
207211

208212
def add_to_class(self, name, value):
@@ -215,8 +219,6 @@ class TopLevelDocumentMetaclass(DocumentMetaclass):
215219
"""
216220

217221
def __new__(cls, name, bases, attrs):
218-
global _document_registry
219-
220222
super_new = super(TopLevelDocumentMetaclass, cls).__new__
221223
# Classes defined in this package are abstract and should not have
222224
# their own metadata with DB collection, etc.
@@ -321,8 +323,6 @@ def __new__(cls, name, bases, attrs):
321323
new_class._fields['id'] = ObjectIdField(db_field='_id')
322324
new_class.id = new_class._fields['id']
323325

324-
_document_registry[name] = new_class
325-
326326
return new_class
327327

328328

mongoengine/connection.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
__all__ = ['ConnectionError', 'connect']
55

66

7-
_connection_settings = {
7+
_connection_defaults = {
88
'host': 'localhost',
99
'port': 27017,
1010
}
1111
_connection = {}
12+
_connection_settings = _connection_defaults.copy()
1213

1314
_db_name = None
1415
_db_username = None
@@ -20,25 +21,25 @@ class ConnectionError(Exception):
2021
pass
2122

2223

23-
def _get_connection():
24+
def _get_connection(reconnect=False):
2425
global _connection
2526
identity = get_identity()
2627
# Connect to the database if not already connected
27-
if _connection.get(identity) is None:
28+
if _connection.get(identity) is None or reconnect:
2829
try:
2930
_connection[identity] = Connection(**_connection_settings)
3031
except:
3132
raise ConnectionError('Cannot connect to the database')
3233
return _connection[identity]
3334

34-
def _get_db():
35+
def _get_db(reconnect=False):
3536
global _db, _connection
3637
identity = get_identity()
3738
# Connect if not already connected
38-
if _connection.get(identity) is None:
39-
_connection[identity] = _get_connection()
39+
if _connection.get(identity) is None or reconnect:
40+
_connection[identity] = _get_connection(reconnect=reconnect)
4041

41-
if _db.get(identity) is None:
42+
if _db.get(identity) is None or reconnect:
4243
# _db_name will be None if the user hasn't called connect()
4344
if _db_name is None:
4445
raise ConnectionError('Not connected to the database')
@@ -61,9 +62,10 @@ def connect(db, username=None, password=None, **kwargs):
6162
the default port on localhost. If authentication is needed, provide
6263
username and password arguments as well.
6364
"""
64-
global _connection_settings, _db_name, _db_username, _db_password
65-
_connection_settings.update(kwargs)
65+
global _connection_settings, _db_name, _db_username, _db_password, _db
66+
_connection_settings = dict(_connection_defaults, **kwargs)
6667
_db_name = db
6768
_db_username = username
6869
_db_password = password
69-
return _get_db()
70+
return _get_db(reconnect=True)
71+

0 commit comments

Comments
 (0)