| @@ -4,6 +4,7 @@ Changelog | |||||||
|  |  | ||||||
| Changes in 0.6.X | Changes in 0.6.X | ||||||
| ================ | ================ | ||||||
|  | - Fixed indexing on '_id' or 'pk' or 'id' | ||||||
| - Invalid data from the DB now raises a InvalidDocumentError | - Invalid data from the DB now raises a InvalidDocumentError | ||||||
| - Cleaned up the Validation Error - docs and code | - Cleaned up the Validation Error - docs and code | ||||||
| - Added meta `auto_create_index` so you can disable index creation | - Added meta `auto_create_index` so you can disable index creation | ||||||
|   | |||||||
| @@ -394,61 +394,6 @@ class QuerySet(object): | |||||||
|             unique=index_spec.get('unique', False)) |             unique=index_spec.get('unique', False)) | ||||||
|         return self |         return self | ||||||
|  |  | ||||||
|     @classmethod |  | ||||||
|     def _build_index_spec(cls, doc_cls, spec): |  | ||||||
|         """Build a PyMongo index spec from a MongoEngine index spec. |  | ||||||
|         """ |  | ||||||
|         if isinstance(spec, basestring): |  | ||||||
|             spec = {'fields': [spec]} |  | ||||||
|         if isinstance(spec, (list, tuple)): |  | ||||||
|             spec = {'fields': spec} |  | ||||||
|  |  | ||||||
|         index_list = [] |  | ||||||
|         use_types = doc_cls._meta.get('allow_inheritance', True) |  | ||||||
|         for key in spec['fields']: |  | ||||||
|             # Get ASCENDING direction from +, DESCENDING from -, and GEO2D from * |  | ||||||
|             direction = pymongo.ASCENDING |  | ||||||
|             if key.startswith("-"): |  | ||||||
|                 direction = pymongo.DESCENDING |  | ||||||
|             elif key.startswith("*"): |  | ||||||
|                 direction = pymongo.GEO2D |  | ||||||
|             if key.startswith(("+", "-", "*")): |  | ||||||
|                 key = key[1:] |  | ||||||
|  |  | ||||||
|             # Use real field name, do it manually because we need field |  | ||||||
|             # objects for the next part (list field checking) |  | ||||||
|             parts = key.split('.') |  | ||||||
|             fields = QuerySet._lookup_field(doc_cls, parts) |  | ||||||
|             parts = [field.db_field for field in fields] |  | ||||||
|             key = '.'.join(parts) |  | ||||||
|             index_list.append((key, direction)) |  | ||||||
|  |  | ||||||
|             # Check if a list field is being used, don't use _types if it is |  | ||||||
|             if use_types and not all(f._index_with_types for f in fields): |  | ||||||
|                 use_types = False |  | ||||||
|  |  | ||||||
|         # If _types is being used, prepend it to every specified index |  | ||||||
|         index_types = doc_cls._meta.get('index_types', True) |  | ||||||
|         allow_inheritance = doc_cls._meta.get('allow_inheritance') |  | ||||||
|         if spec.get('types', index_types) and allow_inheritance and use_types and direction is not pymongo.GEO2D: |  | ||||||
|             index_list.insert(0, ('_types', 1)) |  | ||||||
|  |  | ||||||
|         spec['fields'] = index_list |  | ||||||
|  |  | ||||||
|         if spec.get('sparse', False) and len(spec['fields']) > 1: |  | ||||||
|             raise ValueError( |  | ||||||
|                 'Sparse indexes can only have one field in them. ' |  | ||||||
|                 'See https://jira.mongodb.org/browse/SERVER-2193') |  | ||||||
|  |  | ||||||
|         return spec |  | ||||||
|  |  | ||||||
|     @classmethod |  | ||||||
|     def _reset_already_indexed(cls, document=None): |  | ||||||
|         """Helper to reset already indexed, can be useful for testing purposes""" |  | ||||||
|         if document: |  | ||||||
|             cls.__already_indexed.discard(document) |  | ||||||
|         cls.__already_indexed.clear() |  | ||||||
|  |  | ||||||
|     def __call__(self, q_obj=None, class_check=True, slave_okay=False, **query): |     def __call__(self, q_obj=None, class_check=True, slave_okay=False, **query): | ||||||
|         """Filter the selected documents by calling the |         """Filter the selected documents by calling the | ||||||
|         :class:`~mongoengine.queryset.QuerySet` with a query. |         :class:`~mongoengine.queryset.QuerySet` with a query. | ||||||
| @@ -534,6 +479,62 @@ class QuerySet(object): | |||||||
|             self._collection.ensure_index(index_spec, |             self._collection.ensure_index(index_spec, | ||||||
|                 background=background, **index_opts) |                 background=background, **index_opts) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def _build_index_spec(cls, doc_cls, spec): | ||||||
|  |         """Build a PyMongo index spec from a MongoEngine index spec. | ||||||
|  |         """ | ||||||
|  |         if isinstance(spec, basestring): | ||||||
|  |             spec = {'fields': [spec]} | ||||||
|  |         if isinstance(spec, (list, tuple)): | ||||||
|  |             spec = {'fields': spec} | ||||||
|  |  | ||||||
|  |         index_list = [] | ||||||
|  |         use_types = doc_cls._meta.get('allow_inheritance', True) | ||||||
|  |         for key in spec['fields']: | ||||||
|  |             # Get ASCENDING direction from +, DESCENDING from -, and GEO2D from * | ||||||
|  |             direction = pymongo.ASCENDING | ||||||
|  |             if key.startswith("-"): | ||||||
|  |                 direction = pymongo.DESCENDING | ||||||
|  |             elif key.startswith("*"): | ||||||
|  |                 direction = pymongo.GEO2D | ||||||
|  |             if key.startswith(("+", "-", "*")): | ||||||
|  |                 key = key[1:] | ||||||
|  |  | ||||||
|  |             # Use real field name, do it manually because we need field | ||||||
|  |             # objects for the next part (list field checking) | ||||||
|  |             parts = key.split('.') | ||||||
|  |             fields = QuerySet._lookup_field(doc_cls, parts) | ||||||
|  |             parts = [field if field == '_id' else field.db_field for field in fields] | ||||||
|  |             key = '.'.join(parts) | ||||||
|  |             index_list.append((key, direction)) | ||||||
|  |  | ||||||
|  |             # Check if a list field is being used, don't use _types if it is | ||||||
|  |             if use_types and not all(f._index_with_types for f in fields): | ||||||
|  |                 use_types = False | ||||||
|  |  | ||||||
|  |         # If _types is being used, prepend it to every specified index | ||||||
|  |         index_types = doc_cls._meta.get('index_types', True) | ||||||
|  |         allow_inheritance = doc_cls._meta.get('allow_inheritance') | ||||||
|  |         if spec.get('types', index_types) and allow_inheritance and use_types and direction is not pymongo.GEO2D: | ||||||
|  |             index_list.insert(0, ('_types', 1)) | ||||||
|  |  | ||||||
|  |         spec['fields'] = index_list | ||||||
|  |         if spec.get('sparse', False) and len(spec['fields']) > 1: | ||||||
|  |             raise ValueError( | ||||||
|  |                 'Sparse indexes can only have one field in them. ' | ||||||
|  |                 'See https://jira.mongodb.org/browse/SERVER-2193') | ||||||
|  |  | ||||||
|  |         return spec | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def _reset_already_indexed(cls, document=None): | ||||||
|  |         """Helper to reset already indexed, can be useful for testing purposes""" | ||||||
|  |         if document: | ||||||
|  |             cls.__already_indexed.discard(document) | ||||||
|  |         cls.__already_indexed.clear() | ||||||
|  |  | ||||||
|  |  | ||||||
|     @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 | ||||||
| @@ -613,10 +614,11 @@ class QuerySet(object): | |||||||
|                 continue |                 continue | ||||||
|             if field is None: |             if field is None: | ||||||
|                 # Look up first field from the document |                 # Look up first field from the document | ||||||
|                 if field_name == 'pk': |                 if field_name in ('pk', 'id', '_id'): | ||||||
|                     # Deal with "primary key" alias |                     # Deal with "primary key" alias | ||||||
|                     field_name = document._meta['id_field'] |                     field_name = document._meta['id_field'] or '_id' | ||||||
|                 if field_name in document._fields: |                     field = "_id" | ||||||
|  |                 elif field_name in document._fields: | ||||||
|                     field = document._fields[field_name] |                     field = document._fields[field_name] | ||||||
|                 elif document._dynamic: |                 elif document._dynamic: | ||||||
|                     from base import BaseDynamicField |                     from base import BaseDynamicField | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							| @@ -48,6 +48,6 @@ setup(name='mongoengine', | |||||||
|       platforms=['any'], |       platforms=['any'], | ||||||
|       classifiers=CLASSIFIERS, |       classifiers=CLASSIFIERS, | ||||||
|       install_requires=['pymongo'], |       install_requires=['pymongo'], | ||||||
|       test_suite='tests', |       test_suite='tests.bugfix', | ||||||
|       tests_require=['blinker', 'django>=1.3', 'PIL'] |       tests_require=['blinker', 'django>=1.3', 'PIL'] | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -864,6 +864,26 @@ class DocumentTest(unittest.TestCase): | |||||||
|         query_plan = Test.objects(a=1).only('a').exclude('id').explain() |         query_plan = Test.objects(a=1).only('a').exclude('id').explain() | ||||||
|         self.assertTrue(query_plan['indexOnly']) |         self.assertTrue(query_plan['indexOnly']) | ||||||
|  |  | ||||||
|  |     def test_index_on_id(self): | ||||||
|  |  | ||||||
|  |         class BlogPost(Document): | ||||||
|  |             meta = { | ||||||
|  |                 'indexes': [ | ||||||
|  |                     ['categories', 'id'] | ||||||
|  |                 ], | ||||||
|  |                 'allow_inheritance': False | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             title = StringField(required=True) | ||||||
|  |             description = StringField(required=True) | ||||||
|  |             categories = ListField() | ||||||
|  |  | ||||||
|  |         BlogPost.drop_collection() | ||||||
|  |  | ||||||
|  |         indexes = BlogPost.objects._collection.index_information() | ||||||
|  |         self.assertEquals(indexes['categories_1__id_1']['key'], | ||||||
|  |                                  [('categories', 1), ('_id', 1)]) | ||||||
|  |  | ||||||
|     def test_hint(self): |     def test_hint(self): | ||||||
|  |  | ||||||
|         class BlogPost(Document): |         class BlogPost(Document): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user