Merge branch 'master' of github.com:MongoEngine/mongoengine into release_0_19_0
This commit is contained in:
		@@ -744,7 +744,7 @@ Document inheritance
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
To create a specialised type of a :class:`~mongoengine.Document` you have
 | 
					To create a specialised type of a :class:`~mongoengine.Document` you have
 | 
				
			||||||
defined, you may subclass it and add any extra fields or methods you may need.
 | 
					defined, you may subclass it and add any extra fields or methods you may need.
 | 
				
			||||||
As this is new class is not a direct subclass of
 | 
					As this new class is not a direct subclass of
 | 
				
			||||||
:class:`~mongoengine.Document`, it will not be stored in its own collection; it
 | 
					:class:`~mongoengine.Document`, it will not be stored in its own collection; it
 | 
				
			||||||
will use the same collection as its superclass uses. This allows for more
 | 
					will use the same collection as its superclass uses. This allows for more
 | 
				
			||||||
convenient and efficient retrieval of related documents -- all you need do is
 | 
					convenient and efficient retrieval of related documents -- all you need do is
 | 
				
			||||||
@@ -767,6 +767,27 @@ document.::
 | 
				
			|||||||
          Setting :attr:`allow_inheritance` to True should also be used in
 | 
					          Setting :attr:`allow_inheritance` to True should also be used in
 | 
				
			||||||
          :class:`~mongoengine.EmbeddedDocument` class in case you need to subclass it
 | 
					          :class:`~mongoengine.EmbeddedDocument` class in case you need to subclass it
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When it comes to querying using :attr:`.objects()`, querying `Page.objects()` will query
 | 
				
			||||||
 | 
					both `Page` and `DatedPage` whereas querying `DatedPage` will only query the `DatedPage` documents.
 | 
				
			||||||
 | 
					Behind the scenes, MongoEngine deals with inheritance by adding a :attr:`_cls` attribute that contains
 | 
				
			||||||
 | 
					the class name in every documents. When a document is loaded, MongoEngine checks
 | 
				
			||||||
 | 
					it's :attr:`_cls` attribute and use that class to construct the instance.::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Page(title='a funky title').save()
 | 
				
			||||||
 | 
					    DatedPage(title='another title', date=datetime.utcnow()).save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print(Page.objects().count())         # 2
 | 
				
			||||||
 | 
					    print(DatedPage.objects().count())    # 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # print documents in their native form
 | 
				
			||||||
 | 
					    # we remove 'id' to avoid polluting the output with unnecessary detail
 | 
				
			||||||
 | 
					    qs = Page.objects.exclude('id').as_pymongo()
 | 
				
			||||||
 | 
					    print(list(qs))
 | 
				
			||||||
 | 
					    # [
 | 
				
			||||||
 | 
					    #   {'_cls': u 'Page', 'title': 'a funky title'},
 | 
				
			||||||
 | 
					    #   {'_cls': u 'Page.DatedPage', 'title': u 'another title', 'date': datetime.datetime(2019, 12, 13, 20, 16, 59, 993000)}
 | 
				
			||||||
 | 
					    # ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Working with existing data
 | 
					Working with existing data
 | 
				
			||||||
--------------------------
 | 
					--------------------------
 | 
				
			||||||
As MongoEngine no longer defaults to needing :attr:`_cls`, you can quickly and
 | 
					As MongoEngine no longer defaults to needing :attr:`_cls`, you can quickly and
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ or with an alias:
 | 
				
			|||||||
    conn = get_connection('testdb')
 | 
					    conn = get_connection('testdb')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example of test file:
 | 
					Example of test file:
 | 
				
			||||||
--------
 | 
					---------------------
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    import unittest
 | 
					    import unittest
 | 
				
			||||||
@@ -45,4 +45,4 @@ Example of test file:
 | 
				
			|||||||
            pers.save()
 | 
					            pers.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            fresh_pers = Person.objects().first()
 | 
					            fresh_pers = Person.objects().first()
 | 
				
			||||||
            self.assertEqual(fresh_pers.name, 'John')
 | 
					            assert fresh_pers.name ==  'John'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -222,6 +222,18 @@ keyword argument::
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.. versionadded:: 0.4
 | 
					.. versionadded:: 0.4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sorting/Ordering results
 | 
				
			||||||
 | 
					========================
 | 
				
			||||||
 | 
					It is possible to order the results by 1 or more keys using :meth:`~mongoengine.queryset.QuerySet.order_by`.
 | 
				
			||||||
 | 
					The order may be specified by prepending each of the keys by "+" or "-". Ascending order is assumed if there's no prefix.::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Order by ascending date
 | 
				
			||||||
 | 
					    blogs = BlogPost.objects().order_by('date')    # equivalent to .order_by('+date')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Order by ascending date first, then descending title
 | 
				
			||||||
 | 
					    blogs = BlogPost.objects().order_by('+date', '-title')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Limiting and skipping results
 | 
					Limiting and skipping results
 | 
				
			||||||
=============================
 | 
					=============================
 | 
				
			||||||
Just as with traditional ORMs, you may limit the number of results returned or
 | 
					Just as with traditional ORMs, you may limit the number of results returned or
 | 
				
			||||||
@@ -585,7 +597,8 @@ cannot use the `$` syntax in keyword arguments it has been mapped to `S`::
 | 
				
			|||||||
    ['database', 'mongodb']
 | 
					    ['database', 'mongodb']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
From MongoDB version 2.6, push operator supports $position value which allows
 | 
					From MongoDB version 2.6, push operator supports $position value which allows
 | 
				
			||||||
to push values with index.
 | 
					to push values with index::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    >>> post = BlogPost(title="Test", tags=["mongo"])
 | 
					    >>> post = BlogPost(title="Test", tags=["mongo"])
 | 
				
			||||||
    >>> post.save()
 | 
					    >>> post.save()
 | 
				
			||||||
    >>> post.update(push__tags__0=["database", "code"])
 | 
					    >>> post.update(push__tags__0=["database", "code"])
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,6 +120,9 @@ class BaseList(list):
 | 
				
			|||||||
        super(BaseList, self).__init__(list_items)
 | 
					        super(BaseList, self).__init__(list_items)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __getitem__(self, key):
 | 
					    def __getitem__(self, key):
 | 
				
			||||||
 | 
					        # change index to positive value because MongoDB does not support negative one
 | 
				
			||||||
 | 
					        if isinstance(key, int) and key < 0:
 | 
				
			||||||
 | 
					            key = len(self) + key
 | 
				
			||||||
        value = super(BaseList, self).__getitem__(key)
 | 
					        value = super(BaseList, self).__getitem__(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if isinstance(key, slice):
 | 
					        if isinstance(key, slice):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,7 +41,7 @@ from tests.utils import MongoDBTestCase, get_as_pymongo
 | 
				
			|||||||
TEST_IMAGE_PATH = os.path.join(os.path.dirname(__file__), "../fields/mongoengine.png")
 | 
					TEST_IMAGE_PATH = os.path.join(os.path.dirname(__file__), "../fields/mongoengine.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestInstance(MongoDBTestCase):
 | 
					class TestDocumentInstance(MongoDBTestCase):
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        class Job(EmbeddedDocument):
 | 
					        class Job(EmbeddedDocument):
 | 
				
			||||||
            name = StringField()
 | 
					            name = StringField()
 | 
				
			||||||
@@ -3338,19 +3338,19 @@ class TestInstance(MongoDBTestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        # worker1.job should be equal to the job used originally to create the
 | 
					        # worker1.job should be equal to the job used originally to create the
 | 
				
			||||||
        # document.
 | 
					        # document.
 | 
				
			||||||
        self.assertEqual(worker1.job, worker.job)
 | 
					        assert worker1.job == worker.job
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # worker1.job should be equal to a newly created Job EmbeddedDocument
 | 
					        # worker1.job should be equal to a newly created Job EmbeddedDocument
 | 
				
			||||||
        # using either the Boss object or his ID.
 | 
					        # using either the Boss object or his ID.
 | 
				
			||||||
        self.assertEqual(worker1.job, Job(boss=boss, boss_dbref=boss))
 | 
					        assert worker1.job == Job(boss=boss, boss_dbref=boss)
 | 
				
			||||||
        self.assertEqual(worker1.job, Job(boss=boss.id, boss_dbref=boss.id))
 | 
					        assert worker1.job == Job(boss=boss.id, boss_dbref=boss.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # The above equalities should also hold after worker1.job.boss has been
 | 
					        # The above equalities should also hold after worker1.job.boss has been
 | 
				
			||||||
        # fetch()ed.
 | 
					        # fetch()ed.
 | 
				
			||||||
        worker1.job.boss.fetch()
 | 
					        worker1.job.boss.fetch()
 | 
				
			||||||
        self.assertEqual(worker1.job, worker.job)
 | 
					        assert worker1.job == worker.job
 | 
				
			||||||
        self.assertEqual(worker1.job, Job(boss=boss, boss_dbref=boss))
 | 
					        assert worker1.job == Job(boss=boss, boss_dbref=boss)
 | 
				
			||||||
        self.assertEqual(worker1.job, Job(boss=boss.id, boss_dbref=boss.id))
 | 
					        assert worker1.job == Job(boss=boss.id, boss_dbref=boss.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_dbref_equality(self):
 | 
					    def test_dbref_equality(self):
 | 
				
			||||||
        class Test2(Document):
 | 
					        class Test2(Document):
 | 
				
			||||||
@@ -3617,6 +3617,51 @@ class TestInstance(MongoDBTestCase):
 | 
				
			|||||||
            assert b._instance == a
 | 
					            assert b._instance == a
 | 
				
			||||||
        assert idx == 2
 | 
					        assert idx == 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_updating_listfield_manipulate_list(self):
 | 
				
			||||||
 | 
					        class Company(Document):
 | 
				
			||||||
 | 
					            name = StringField()
 | 
				
			||||||
 | 
					            employees = ListField(field=DictField())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Company.drop_collection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        comp = Company(name="BigBank", employees=[{"name": "John"}])
 | 
				
			||||||
 | 
					        comp.save()
 | 
				
			||||||
 | 
					        comp.employees.append({"name": "Bill"})
 | 
				
			||||||
 | 
					        comp.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stored_comp = get_as_pymongo(comp)
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            stored_comp,
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "_id": comp.id,
 | 
				
			||||||
 | 
					                "employees": [{"name": "John"}, {"name": "Bill"}],
 | 
				
			||||||
 | 
					                "name": "BigBank",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        comp = comp.reload()
 | 
				
			||||||
 | 
					        comp.employees[0]["color"] = "red"
 | 
				
			||||||
 | 
					        comp.employees[-1]["color"] = "blue"
 | 
				
			||||||
 | 
					        comp.employees[-1].update({"size": "xl"})
 | 
				
			||||||
 | 
					        comp.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert len(comp.employees) == 2
 | 
				
			||||||
 | 
					        assert comp.employees[0] == {"name": "John", "color": "red"}
 | 
				
			||||||
 | 
					        assert comp.employees[1] == {"name": "Bill", "size": "xl", "color": "blue"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stored_comp = get_as_pymongo(comp)
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            stored_comp,
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "_id": comp.id,
 | 
				
			||||||
 | 
					                "employees": [
 | 
				
			||||||
 | 
					                    {"name": "John", "color": "red"},
 | 
				
			||||||
 | 
					                    {"size": "xl", "color": "blue", "name": "Bill"},
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "name": "BigBank",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_falsey_pk(self):
 | 
					    def test_falsey_pk(self):
 | 
				
			||||||
        """Ensure that we can create and update a document with Falsey PK."""
 | 
					        """Ensure that we can create and update a document with Falsey PK."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3693,13 +3738,13 @@ class TestInstance(MongoDBTestCase):
 | 
				
			|||||||
        value = u"I_should_be_a_dict"
 | 
					        value = u"I_should_be_a_dict"
 | 
				
			||||||
        coll.insert_one({"light_saber": value})
 | 
					        coll.insert_one({"light_saber": value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with self.assertRaises(InvalidDocumentError) as cm:
 | 
					        with pytest.raises(InvalidDocumentError) as exc_info:
 | 
				
			||||||
            list(Jedi.objects)
 | 
					            list(Jedi.objects)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(
 | 
					        assert str(
 | 
				
			||||||
            str(cm.exception),
 | 
					            exc_info.value
 | 
				
			||||||
            "Invalid data to create a `Jedi` instance.\nField 'light_saber' - The source SON object needs to be of type 'dict' but a '%s' was found"
 | 
					        ) == "Invalid data to create a `Jedi` instance.\nField 'light_saber' - The source SON object needs to be of type 'dict' but a '%s' was found" % type(
 | 
				
			||||||
            % type(value),
 | 
					            value
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -151,7 +151,7 @@ class TestFileField(MongoDBTestCase):
 | 
				
			|||||||
        result = StreamFile.objects.first()
 | 
					        result = StreamFile.objects.first()
 | 
				
			||||||
        assert streamfile == result
 | 
					        assert streamfile == result
 | 
				
			||||||
        assert result.the_file.read() == text + more_text
 | 
					        assert result.the_file.read() == text + more_text
 | 
				
			||||||
        # self.assertEqual(result.the_file.content_type, content_type)
 | 
					        # assert result.the_file.content_type == content_type
 | 
				
			||||||
        result.the_file.seek(0)
 | 
					        result.the_file.seek(0)
 | 
				
			||||||
        assert result.the_file.tell() == 0
 | 
					        assert result.the_file.tell() == 0
 | 
				
			||||||
        assert result.the_file.read(len(text)) == text
 | 
					        assert result.the_file.read(len(text)) == text
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user