Add new meta option to Document: allow_index_creation.

Defaults to True. If set to False then MongoEngine will not ensure indexes exist
This commit is contained in:
Colin Howe 2012-03-19 20:27:08 +00:00
parent 61411bb259
commit 7e376b40bb
3 changed files with 77 additions and 47 deletions

View File

@ -74,6 +74,11 @@ 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.
Index creation can be disabled by specifying :attr:`index_allow_creation` in
the :attr:`meta` dictionary. If this is set to True 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

View File

@ -481,13 +481,60 @@ class QuerySet(object):
"""Returns all documents.""" """Returns all documents."""
return self.__call__() return self.__call__()
def _ensure_indexes_exist(self):
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_options', {})
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 +543,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('index_allow_creation', True):
drop_dups = self._document._meta.get('index_drop_dups', False) self._ensure_indexes_exist()
index_opts = self._document._meta.get('index_options', {})
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

View File

@ -740,6 +740,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 allow_index_creation to False on the connection will
disable any index generation.
"""
class User(Document):
meta = {
'indexes': ['user_guid'],
'index_allow_creation': 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
""" """