diff --git a/AUTHORS b/AUTHORS index fe8be767..ab0469e9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -114,4 +114,5 @@ that much better: * Jaime Irurzun * Alexandre González * Thomas Steinacher - * Tommi Komulainen \ No newline at end of file + * Tommi Komulainen + * Peter Landry diff --git a/README.rst b/README.rst index 548737cd..1305b6e9 100644 --- a/README.rst +++ b/README.rst @@ -2,6 +2,7 @@ MongoEngine =========== :Info: MongoEngine is an ORM-like layer on top of PyMongo. +:Repository: https://github.com/MongoEngine/mongoengine :Author: Harry Marr (http://github.com/hmarr) :Maintainer: Ross Lawley (http://github.com/rozza) diff --git a/docs/changelog.rst b/docs/changelog.rst index 08091acb..c05da946 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,8 +2,14 @@ Changelog ========= -Changes in 0.6.X -================ +Changes in 0.6.20 +================= +- Added support for distinct and db_alias (MongoEngine/mongoengine#59) +- Improved support for chained querysets when constraining the same fields (hmarr/mongoengine#554) +- Fixed BinaryField lookup re (MongoEngine/mongoengine#48) + +Changes in 0.6.19 +================= - Added Binary support to UUID (MongoEngine/mongoengine#47) - Fixed MapField lookup for fields without declared lookups (MongoEngine/mongoengine#46) diff --git a/docs/guide/querying.rst b/docs/guide/querying.rst index a9567e20..14498017 100644 --- a/docs/guide/querying.rst +++ b/docs/guide/querying.rst @@ -232,7 +232,7 @@ custom manager methods as you like:: BlogPost(title='test1', published=False).save() BlogPost(title='test2', published=True).save() assert len(BlogPost.objects) == 2 - assert len(BlogPost.live_posts) == 1 + assert len(BlogPost.live_posts()) == 1 Custom QuerySets ================ @@ -243,11 +243,16 @@ a document, set ``queryset_class`` to the custom class in a :class:`~mongoengine.Document`\ s ``meta`` dictionary:: class AwesomerQuerySet(QuerySet): - pass + + def get_awesome(self): + return self.filter(awesome=True) class Page(Document): meta = {'queryset_class': AwesomerQuerySet} + # To call: + Page.objects.get_awesome() + .. versionadded:: 0.4 Aggregation diff --git a/mongoengine/__init__.py b/mongoengine/__init__.py index 5f4f7f1d..ea3dd5e6 100644 --- a/mongoengine/__init__.py +++ b/mongoengine/__init__.py @@ -12,7 +12,7 @@ from signals import * __all__ = (document.__all__ + fields.__all__ + connection.__all__ + queryset.__all__ + signals.__all__) -VERSION = (0, 6, 18) +VERSION = (0, 6, 20) def get_version(): diff --git a/mongoengine/dereference.py b/mongoengine/dereference.py index f74e224c..637380d6 100644 --- a/mongoengine/dereference.py +++ b/mongoengine/dereference.py @@ -34,7 +34,9 @@ class DeReference(object): doc_type = None if instance and instance._fields: - doc_type = instance._fields[name].field + doc_type = instance._fields[name] + if hasattr(doc_type, 'field'): + doc_type = doc_type.field if isinstance(doc_type, ReferenceField): doc_type = doc_type.document_type diff --git a/mongoengine/fields.py b/mongoengine/fields.py index 82689929..8e3cf15a 100644 --- a/mongoengine/fields.py +++ b/mongoengine/fields.py @@ -1327,7 +1327,7 @@ class UUIDField(BaseField): super(UUIDField, self).__init__(**kwargs) def to_python(self, value): - if not self.binary: + if not self._binary: if not isinstance(value, basestring): value = unicode(value) return uuid.UUID(value) diff --git a/mongoengine/queryset.py b/mongoengine/queryset.py index 366dd21a..95bb58a4 100644 --- a/mongoengine/queryset.py +++ b/mongoengine/queryset.py @@ -765,8 +765,22 @@ class QuerySet(object): key = '.'.join(parts) if op is None or key not in mongo_query: mongo_query[key] = value - elif key in mongo_query and isinstance(mongo_query[key], dict): - mongo_query[key].update(value) + elif key in mongo_query: + if isinstance(mongo_query[key], dict) and isinstance(value, dict): + mongo_query[key].update(value) + elif isinstance(mongo_query[key], list): + mongo_query[key].append(value) + else: + mongo_query[key] = [mongo_query[key], value] + + for k, v in mongo_query.items(): + if isinstance(v, list): + value = [{k:val} for val in v] + if '$and' in mongo_query.keys(): + mongo_query['$and'].append(value) + else: + mongo_query['$and'] = value + del mongo_query[k] return mongo_query @@ -1152,8 +1166,10 @@ class QuerySet(object): .. versionadded:: 0.4 .. versionchanged:: 0.5 - Fixed handling references + .. versionchanged:: 0.6 - Improved db_field refrence handling """ - return self._dereference(self._cursor.distinct(field), 1) + return self._dereference(self._cursor.distinct(field), 1, + name=field, instance=self._document) def only(self, *fields): """Load only a subset of this document's fields. :: @@ -1866,6 +1882,17 @@ class QuerySet(object): class QuerySetManager(object): + """ + The default QuerySet Manager. + + Custom QuerySet Manager functions can extend this class and users can + add extra queryset functionality. Any custom manager methods must accept a + :class:`~mongoengine.Document` class as its first argument, and a + :class:`~mongoengine.queryset.QuerySet` as its second argument. + + The method function should return a :class:`~mongoengine.queryset.QuerySet` + , probably the same one that was passed in, but modified in some way. + """ get_queryset = None diff --git a/python-mongoengine.spec b/python-mongoengine.spec index 4dfbeccc..4e803263 100644 --- a/python-mongoengine.spec +++ b/python-mongoengine.spec @@ -5,7 +5,7 @@ %define srcname mongoengine Name: python-%{srcname} -Version: 0.6.18 +Version: 0.6.20 Release: 1%{?dist} Summary: A Python Document-Object Mapper for working with MongoDB diff --git a/tests/test_fields.py b/tests/test_fields.py index c4013c10..a6eaca43 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -283,6 +283,7 @@ class FieldTest(unittest.TestCase): uu = uuid.uuid4() Person(api_key=uu).save() self.assertEqual(1, Person.objects(api_key=uu).count()) + self.assertEqual(uu, Person.objects.first().api_key) person = Person() valid = (uuid.uuid4(), uuid.uuid1()) @@ -307,6 +308,7 @@ class FieldTest(unittest.TestCase): uu = uuid.uuid4() Person(api_key=uu).save() self.assertEqual(1, Person.objects(api_key=uu).count()) + self.assertEqual(uu, Person.objects.first().api_key) person = Person() valid = (uuid.uuid4(), uuid.uuid1()) diff --git a/tests/test_queryset.py b/tests/test_queryset.py index b4ae805b..8f846ea6 100644 --- a/tests/test_queryset.py +++ b/tests/test_queryset.py @@ -827,7 +827,11 @@ class QuerySetTest(unittest.TestCase): def test_filter_chaining(self): """Ensure filters can be chained together. """ + class Blog(Document): + id = StringField(unique=True, primary_key=True) + class BlogPost(Document): + blog = ReferenceField(Blog) title = StringField() is_published = BooleanField() published_date = DateTimeField() @@ -836,13 +840,24 @@ class QuerySetTest(unittest.TestCase): def published(doc_cls, queryset): return queryset(is_published=True) - blog_post_1 = BlogPost(title="Blog Post #1", + Blog.drop_collection() + BlogPost.drop_collection() + + blog_1 = Blog(id="1") + blog_2 = Blog(id="2") + blog_3 = Blog(id="3") + + blog_1.save() + blog_2.save() + blog_3.save() + + blog_post_1 = BlogPost(blog=blog_1, title="Blog Post #1", is_published = True, published_date=datetime(2010, 1, 5, 0, 0 ,0)) - blog_post_2 = BlogPost(title="Blog Post #2", + blog_post_2 = BlogPost(blog=blog_2, title="Blog Post #2", is_published = True, published_date=datetime(2010, 1, 6, 0, 0 ,0)) - blog_post_3 = BlogPost(title="Blog Post #3", + blog_post_3 = BlogPost(blog=blog_3, title="Blog Post #3", is_published = True, published_date=datetime(2010, 1, 7, 0, 0 ,0)) @@ -856,7 +871,14 @@ class QuerySetTest(unittest.TestCase): published_date__lt=datetime(2010, 1, 7, 0, 0 ,0)) self.assertEqual(published_posts.count(), 2) + + blog_posts = BlogPost.objects + blog_posts = blog_posts.filter(blog__in=[blog_1, blog_2]) + blog_posts = blog_posts.filter(blog=blog_3) + self.assertEqual(blog_posts.count(), 0) + BlogPost.drop_collection() + Blog.drop_collection() def test_ordering(self): """Ensure default ordering is applied and can be overridden. @@ -2277,6 +2299,28 @@ class QuerySetTest(unittest.TestCase): self.assertEquals(Foo.objects.distinct("bar"), [bar]) + def test_distinct_handles_references_to_alias(self): + register_connection('testdb', 'mongoenginetest2') + + class Foo(Document): + bar = ReferenceField("Bar") + meta = {'db_alias': 'testdb'} + + class Bar(Document): + text = StringField() + meta = {'db_alias': 'testdb'} + + Bar.drop_collection() + Foo.drop_collection() + + bar = Bar(text="hi") + bar.save() + + foo = Foo(bar=bar) + foo.save() + + self.assertEquals(Foo.objects.distinct("bar"), [bar]) + def test_custom_manager(self): """Ensure that custom QuerySetManager instances work as expected. """