Fixed inheritance and unique index creation (#140)
This commit is contained in:
@@ -509,6 +509,34 @@ class BaseDocument(object):
|
||||
obj._created = False
|
||||
return obj
|
||||
|
||||
@classmethod
|
||||
def _build_index_specs(cls, meta_indexes):
|
||||
"""Generate and merge the full index specs
|
||||
"""
|
||||
|
||||
geo_indices = cls._geo_indices()
|
||||
unique_indices = cls._unique_with_indexes()
|
||||
index_specs = [cls._build_index_spec(spec)
|
||||
for spec in meta_indexes]
|
||||
|
||||
def merge_index_specs(index_specs, indices):
|
||||
if not indices:
|
||||
return index_specs
|
||||
|
||||
spec_fields = [v['fields']
|
||||
for k, v in enumerate(index_specs)]
|
||||
# Merge unqiue_indexes with existing specs
|
||||
for k, v in enumerate(indices):
|
||||
if v['fields'] in spec_fields:
|
||||
index_specs[spec_fields.index(v['fields'])].update(v)
|
||||
else:
|
||||
index_specs.append(v)
|
||||
return index_specs
|
||||
|
||||
index_specs = merge_index_specs(index_specs, geo_indices)
|
||||
index_specs = merge_index_specs(index_specs, unique_indices)
|
||||
return index_specs
|
||||
|
||||
@classmethod
|
||||
def _build_index_spec(cls, spec):
|
||||
"""Build a PyMongo index spec from a MongoEngine index spec.
|
||||
@@ -576,6 +604,7 @@ class BaseDocument(object):
|
||||
"""
|
||||
unique_indexes = []
|
||||
for field_name, field in cls._fields.items():
|
||||
sparse = False
|
||||
# Generate a list of indexes needed by uniqueness constraints
|
||||
if field.unique:
|
||||
field.required = True
|
||||
@@ -596,11 +625,14 @@ class BaseDocument(object):
|
||||
unique_with.append('.'.join(name_parts))
|
||||
# Unique field should be required
|
||||
parts[-1].required = True
|
||||
sparse = (not sparse and
|
||||
parts[-1].name not in cls.__dict__)
|
||||
unique_fields += unique_with
|
||||
|
||||
# Add the new index to the list
|
||||
index = [("%s%s" % (namespace, f), pymongo.ASCENDING)
|
||||
fields = [("%s%s" % (namespace, f), pymongo.ASCENDING)
|
||||
for f in unique_fields]
|
||||
index = {'fields': fields, 'unique': True, 'sparse': sparse}
|
||||
unique_indexes.append(index)
|
||||
|
||||
# Grab any embedded document field unique indexes
|
||||
@@ -612,6 +644,29 @@ class BaseDocument(object):
|
||||
|
||||
return unique_indexes
|
||||
|
||||
@classmethod
|
||||
def _geo_indices(cls, inspected=None):
|
||||
inspected = inspected or []
|
||||
geo_indices = []
|
||||
inspected.append(cls)
|
||||
|
||||
EmbeddedDocumentField = _import_class("EmbeddedDocumentField")
|
||||
GeoPointField = _import_class("GeoPointField")
|
||||
|
||||
for field in cls._fields.values():
|
||||
if not isinstance(field, (EmbeddedDocumentField, GeoPointField)):
|
||||
continue
|
||||
if hasattr(field, 'document_type'):
|
||||
field_cls = field.document_type
|
||||
if field_cls in inspected:
|
||||
continue
|
||||
if hasattr(field_cls, '_geo_indices'):
|
||||
geo_indices += field_cls._geo_indices(inspected)
|
||||
elif field._geo_index:
|
||||
geo_indices.append({'fields':
|
||||
[(field.db_field, pymongo.GEO2D)]})
|
||||
return geo_indices
|
||||
|
||||
@classmethod
|
||||
def _lookup_field(cls, parts):
|
||||
"""Lookup a field based on its attribute and return a list containing
|
||||
@@ -671,28 +726,6 @@ class BaseDocument(object):
|
||||
parts = [f.db_field for f in cls._lookup_field(parts)]
|
||||
return '.'.join(parts)
|
||||
|
||||
@classmethod
|
||||
def _geo_indices(cls, inspected=None):
|
||||
inspected = inspected or []
|
||||
geo_indices = []
|
||||
inspected.append(cls)
|
||||
|
||||
EmbeddedDocumentField = _import_class("EmbeddedDocumentField")
|
||||
GeoPointField = _import_class("GeoPointField")
|
||||
|
||||
for field in cls._fields.values():
|
||||
if not isinstance(field, (EmbeddedDocumentField, GeoPointField)):
|
||||
continue
|
||||
if hasattr(field, 'document_type'):
|
||||
field_cls = field.document_type
|
||||
if field_cls in inspected:
|
||||
continue
|
||||
if hasattr(field_cls, '_geo_indices'):
|
||||
geo_indices += field_cls._geo_indices(inspected)
|
||||
elif field._geo_index:
|
||||
geo_indices.append(field)
|
||||
return geo_indices
|
||||
|
||||
def __set_field_display(self):
|
||||
"""Dynamically set the display value for a field with choices"""
|
||||
for attr_name, field in self._fields.items():
|
||||
|
||||
@@ -329,10 +329,7 @@ class TopLevelDocumentMetaclass(DocumentMetaclass):
|
||||
meta = new_class._meta
|
||||
|
||||
# Set index specifications
|
||||
meta['index_specs'] = [new_class._build_index_spec(spec)
|
||||
for spec in meta['indexes']]
|
||||
unique_indexes = new_class._unique_with_indexes()
|
||||
new_class._meta['unique_indexes'] = unique_indexes
|
||||
meta['index_specs'] = new_class._build_index_specs(meta['indexes'])
|
||||
|
||||
# If collection is a callable - call it and set the value
|
||||
collection = meta.get('collection')
|
||||
|
||||
Reference in New Issue
Block a user