Merge branch 'dev-disable-indexing' of https://github.com/colinhowe/mongoengine

Conflicts:
	mongoengine/queryset.py
This commit is contained in:
Ross Lawley 2012-05-01 09:37:01 +01:00
commit 4ce1ba81a6
4 changed files with 88 additions and 51 deletions

View File

@ -4,6 +4,7 @@ Changelog
Changes in 0.6.X Changes in 0.6.X
================ ================
- Added meta `auto_create_index` so you can disable index creation
- Added write concern options to inserts - Added write concern options to inserts
- Fixed typo in meta for index options - Fixed typo in meta for index options
- Bug fix Read preference now passed correctly - Bug fix Read preference now passed correctly

View File

@ -74,6 +74,12 @@ class Document(BaseDocument):
names. Index direction may be specified by prefixing the field names with names. Index direction may be specified by prefixing the field names with
a **+** or **-** sign. a **+** or **-** sign.
Automatic index creation can be disabled by specifying
attr:`auto_create_index` in the :attr:`meta` dictionary. If this is set to
False then indexes will not be created by MongoEngine. This is useful in
production systems where index creation is performed as part of a deployment
system.
By default, _types will be added to the start of every index (that By default, _types will be added to the start of every index (that
doesn't contain a list) if allow_inheritence is True. This can be doesn't contain a list) if allow_inheritence is True. This can be
disabled by either setting types to False on the specific index or disabled by either setting types to False on the specific index or
@ -147,8 +153,8 @@ class Document(BaseDocument):
:meth:`~pymongo.collection.Collection.save` OR :meth:`~pymongo.collection.Collection.save` OR
:meth:`~pymongo.collection.Collection.insert` :meth:`~pymongo.collection.Collection.insert`
which will be used as options for the resultant ``getLastError`` command. which will be used as options for the resultant ``getLastError`` command.
For example, ``save(..., write_options={w: 2, fsync: True}, ...)`` will For example, ``save(..., write_options={w: 2, fsync: True}, ...)`` will
wait until at least two servers have recorded the write and will force an wait until at least two servers have recorded the write and will force an
fsync on each server being written to. fsync on each server being written to.
:param cascade: Sets the flag for cascading saves. You can set a default by setting :param cascade: Sets the flag for cascading saves. You can set a default by setting
"cascade" in the document __meta__ "cascade" in the document __meta__

View File

@ -481,13 +481,65 @@ class QuerySet(object):
"""Returns all documents.""" """Returns all documents."""
return self.__call__() return self.__call__()
def _ensure_indexes(self):
"""Checks the document meta data and ensures all the indexes exist.
.. note:: You can disable automatic index creation by setting
`auto_create_index` to False in the documents meta data
"""
background = self._document._meta.get('index_background', False)
drop_dups = self._document._meta.get('index_drop_dups', False)
index_opts = self._document._meta.get('index_opts', {})
index_types = self._document._meta.get('index_types', True)
# determine if an index which we are creating includes
# _type as its first field; if so, we can avoid creating
# an extra index on _type, as mongodb will use the existing
# index to service queries against _type
types_indexed = False
def includes_types(fields):
first_field = None
if len(fields):
if isinstance(fields[0], basestring):
first_field = fields[0]
elif isinstance(fields[0], (list, tuple)) and len(fields[0]):
first_field = fields[0][0]
return first_field == '_types'
# Ensure indexes created by uniqueness constraints
for index in self._document._meta['unique_indexes']:
types_indexed = types_indexed or includes_types(index)
self._collection.ensure_index(index, unique=True,
background=background, drop_dups=drop_dups, **index_opts)
# Ensure document-defined indexes are created
if self._document._meta['indexes']:
for spec in self._document._meta['indexes']:
types_indexed = types_indexed or includes_types(spec['fields'])
opts = index_opts.copy()
opts['unique'] = spec.get('unique', False)
opts['sparse'] = spec.get('sparse', False)
self._collection.ensure_index(spec['fields'],
background=background, **opts)
# If _types is being used (for polymorphism), it needs an index,
# only if another index doesn't begin with _types
if index_types and '_types' in self._query and not types_indexed:
self._collection.ensure_index('_types',
background=background, **index_opts)
# Add geo indicies
for field in self._document._geo_indices():
index_spec = [(field.db_field, pymongo.GEO2D)]
self._collection.ensure_index(index_spec,
background=background, **index_opts)
@property @property
def _collection(self): def _collection(self):
"""Property that returns the collection object. This allows us to """Property that returns the collection object. This allows us to
perform operations only if the collection is accessed. perform operations only if the collection is accessed.
""" """
if self._document not in QuerySet.__already_indexed: if self._document not in QuerySet.__already_indexed:
# Ensure collection exists # Ensure collection exists
db = self._document._get_db() db = self._document._get_db()
if self._collection_obj.name not in db.collection_names(): if self._collection_obj.name not in db.collection_names():
@ -496,52 +548,8 @@ class QuerySet(object):
QuerySet.__already_indexed.add(self._document) QuerySet.__already_indexed.add(self._document)
background = self._document._meta.get('index_background', False) if self._document._meta.get('auto_create_index', True):
drop_dups = self._document._meta.get('index_drop_dups', False) self._ensure_indexes()
index_opts = self._document._meta.get('index_opts', {})
index_types = self._document._meta.get('index_types', True)
# determine if an index which we are creating includes
# _type as its first field; if so, we can avoid creating
# an extra index on _type, as mongodb will use the existing
# index to service queries against _type
types_indexed = False
def includes_types(fields):
first_field = None
if len(fields):
if isinstance(fields[0], basestring):
first_field = fields[0]
elif isinstance(fields[0], (list, tuple)) and len(fields[0]):
first_field = fields[0][0]
return first_field == '_types'
# Ensure indexes created by uniqueness constraints
for index in self._document._meta['unique_indexes']:
types_indexed = types_indexed or includes_types(index)
self._collection.ensure_index(index, unique=True,
background=background, drop_dups=drop_dups, **index_opts)
# Ensure document-defined indexes are created
if self._document._meta['indexes']:
for spec in self._document._meta['indexes']:
types_indexed = types_indexed or includes_types(spec['fields'])
opts = index_opts.copy()
opts['unique'] = spec.get('unique', False)
opts['sparse'] = spec.get('sparse', False)
self._collection.ensure_index(spec['fields'],
background=background, **opts)
# If _types is being used (for polymorphism), it needs an index,
# only if another index doesn't begin with _types
if index_types and '_types' in self._query and not types_indexed:
self._collection.ensure_index('_types',
background=background, **index_opts)
# Add geo indicies
for field in self._document._geo_indices():
index_spec = [(field.db_field, pymongo.GEO2D)]
self._collection.ensure_index(index_spec,
background=background, **index_opts)
return self._collection_obj return self._collection_obj
@ -836,8 +844,8 @@ class QuerySet(object):
:param write_options: Extra keyword arguments are passed down to :param write_options: Extra keyword arguments are passed down to
:meth:`~pymongo.collection.Collection.insert` :meth:`~pymongo.collection.Collection.insert`
which will be used as options for the resultant ``getLastError`` command. which will be used as options for the resultant ``getLastError`` command.
For example, ``insert(..., {w: 2, fsync: True})`` will wait until at least two For example, ``insert(..., {w: 2, fsync: True})`` will wait until at least two
servers have recorded the write and will force an fsync on each server being servers have recorded the write and will force an fsync on each server being
written to. written to.
By default returns document instances, set ``load_bulk`` to False to By default returns document instances, set ``load_bulk`` to False to

View File

@ -741,6 +741,28 @@ class DocumentTest(unittest.TestCase):
self.assertEqual(info.keys(), ['_types_1_user_guid_1', '_id_', '_types_1_name_1']) self.assertEqual(info.keys(), ['_types_1_user_guid_1', '_id_', '_types_1_name_1'])
Person.drop_collection() Person.drop_collection()
def test_disable_index_creation(self):
"""Tests setting auto_create_index to False on the connection will
disable any index generation.
"""
class User(Document):
meta = {
'indexes': ['user_guid'],
'auto_create_index': False
}
user_guid = StringField(required=True)
User.drop_collection()
u = User(user_guid='123')
u.save()
self.assertEquals(1, User.objects.count())
info = User.objects._collection.index_information()
self.assertEqual(info.keys(), ['_id_'])
User.drop_collection()
def test_embedded_document_index(self): def test_embedded_document_index(self):
"""Tests settings an index on an embedded document """Tests settings an index on an embedded document
""" """