Compare commits
35 Commits
cleanup-fi
...
ci-test-ag
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2626eca58e | ||
|
|
d5b1914158 | ||
|
|
e20a34857d | ||
|
|
7d0b533920 | ||
|
|
6a9e02635d | ||
|
|
5a1fdadf8b | ||
|
|
70871f671a | ||
|
|
e6821d8656 | ||
|
|
4f85547333 | ||
|
|
deeb6d026d | ||
|
|
97d9a7cf43 | ||
|
|
7850e47bf7 | ||
|
|
a94ec06275 | ||
|
|
4acd7a5b75 | ||
|
|
e6dcb39036 | ||
|
|
4ed65f8589 | ||
|
|
39586e83cd | ||
|
|
5992fdd408 | ||
|
|
70faaf445e | ||
|
|
71ccfeac3c | ||
|
|
d39f5197cb | ||
|
|
5b4eb02683 | ||
|
|
d0442d7578 | ||
|
|
098a90ee96 | ||
|
|
d7d48e4c21 | ||
|
|
cb62b457bc | ||
|
|
d29c1c1094 | ||
|
|
d6af8cb157 | ||
|
|
8e2e5f506d | ||
|
|
0ea1dfddaa | ||
|
|
ce7142eb4f | ||
|
|
5e17fc6d47 | ||
|
|
ee7bd1bdae | ||
|
|
d75dc02614 | ||
|
|
c08ee77041 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,4 +17,3 @@ tests/test_bugfix.py
|
|||||||
htmlcov/
|
htmlcov/
|
||||||
venv
|
venv
|
||||||
venv3
|
venv3
|
||||||
scratchpad
|
|
||||||
|
|||||||
@@ -42,18 +42,13 @@ the :attr:`host` to
|
|||||||
will establish connection to ``production`` database using
|
will establish connection to ``production`` database using
|
||||||
``admin`` username and ``qwerty`` password.
|
``admin`` username and ``qwerty`` password.
|
||||||
|
|
||||||
Replica Sets
|
ReplicaSets
|
||||||
============
|
===========
|
||||||
|
|
||||||
MongoEngine supports connecting to replica sets::
|
MongoEngine supports
|
||||||
|
:class:`~pymongo.mongo_replica_set_client.MongoReplicaSetClient`. To use them,
|
||||||
from mongoengine import connect
|
please use an URI style connection and provide the ``replicaSet`` name
|
||||||
|
in the connection kwargs.
|
||||||
# Regular connect
|
|
||||||
connect('dbname', replicaset='rs-name')
|
|
||||||
|
|
||||||
# MongoDB URI-style connect
|
|
||||||
connect(host='mongodb://localhost/dbname?replicaSet=rs-name')
|
|
||||||
|
|
||||||
Read preferences are supported through the connection or via individual
|
Read preferences are supported through the connection or via individual
|
||||||
queries by passing the read_preference ::
|
queries by passing the read_preference ::
|
||||||
@@ -64,74 +59,76 @@ queries by passing the read_preference ::
|
|||||||
Multiple Databases
|
Multiple Databases
|
||||||
==================
|
==================
|
||||||
|
|
||||||
To use multiple databases you can use :func:`~mongoengine.connect` and provide
|
Multiple database support was added in MongoEngine 0.6. To use multiple
|
||||||
an `alias` name for the connection - if no `alias` is provided then "default"
|
databases you can use :func:`~mongoengine.connect` and provide an `alias` name
|
||||||
is used.
|
for the connection - if no `alias` is provided then "default" is used.
|
||||||
|
|
||||||
In the background this uses :func:`~mongoengine.register_connection` to
|
In the background this uses :func:`~mongoengine.register_connection` to
|
||||||
store the data and you can register all aliases up front if required.
|
store the data and you can register all aliases up front if required.
|
||||||
|
|
||||||
Individual documents can also support multiple databases by providing a
|
Individual documents can also support multiple databases by providing a
|
||||||
`db_alias` in their meta data. This allows :class:`~pymongo.dbref.DBRef`
|
`db_alias` in their meta data. This allows :class:`~pymongo.dbref.DBRef` objects
|
||||||
objects to point across databases and collections. Below is an example schema,
|
to point across databases and collections. Below is an example schema, using
|
||||||
using 3 different databases to store data::
|
3 different databases to store data::
|
||||||
|
|
||||||
class User(Document):
|
class User(Document):
|
||||||
name = StringField()
|
name = StringField()
|
||||||
|
|
||||||
meta = {'db_alias': 'user-db'}
|
meta = {"db_alias": "user-db"}
|
||||||
|
|
||||||
class Book(Document):
|
class Book(Document):
|
||||||
name = StringField()
|
name = StringField()
|
||||||
|
|
||||||
meta = {'db_alias': 'book-db'}
|
meta = {"db_alias": "book-db"}
|
||||||
|
|
||||||
class AuthorBooks(Document):
|
class AuthorBooks(Document):
|
||||||
author = ReferenceField(User)
|
author = ReferenceField(User)
|
||||||
book = ReferenceField(Book)
|
book = ReferenceField(Book)
|
||||||
|
|
||||||
meta = {'db_alias': 'users-books-db'}
|
meta = {"db_alias": "users-books-db"}
|
||||||
|
|
||||||
|
|
||||||
Context Managers
|
Context Managers
|
||||||
================
|
================
|
||||||
Sometimes you may want to switch the database or collection to query against.
|
Sometimes you may want to switch the database or collection to query against
|
||||||
|
for a class.
|
||||||
For example, archiving older data into a separate database for performance
|
For example, archiving older data into a separate database for performance
|
||||||
reasons or writing functions that dynamically choose collections to write
|
reasons or writing functions that dynamically choose collections to write
|
||||||
a document to.
|
document to.
|
||||||
|
|
||||||
Switch Database
|
Switch Database
|
||||||
---------------
|
---------------
|
||||||
The :class:`~mongoengine.context_managers.switch_db` context manager allows
|
The :class:`~mongoengine.context_managers.switch_db` context manager allows
|
||||||
you to change the database alias for a given class allowing quick and easy
|
you to change the database alias for a given class allowing quick and easy
|
||||||
access to the same User document across databases::
|
access the same User document across databases::
|
||||||
|
|
||||||
from mongoengine.context_managers import switch_db
|
from mongoengine.context_managers import switch_db
|
||||||
|
|
||||||
class User(Document):
|
class User(Document):
|
||||||
name = StringField()
|
name = StringField()
|
||||||
|
|
||||||
meta = {'db_alias': 'user-db'}
|
meta = {"db_alias": "user-db"}
|
||||||
|
|
||||||
with switch_db(User, 'archive-user-db') as User:
|
with switch_db(User, 'archive-user-db') as User:
|
||||||
User(name='Ross').save() # Saves the 'archive-user-db'
|
User(name="Ross").save() # Saves the 'archive-user-db'
|
||||||
|
|
||||||
|
|
||||||
Switch Collection
|
Switch Collection
|
||||||
-----------------
|
-----------------
|
||||||
The :class:`~mongoengine.context_managers.switch_collection` context manager
|
The :class:`~mongoengine.context_managers.switch_collection` context manager
|
||||||
allows you to change the collection for a given class allowing quick and easy
|
allows you to change the collection for a given class allowing quick and easy
|
||||||
access to the same Group document across collection::
|
access the same Group document across collection::
|
||||||
|
|
||||||
from mongoengine.context_managers import switch_collection
|
from mongoengine.context_managers import switch_collection
|
||||||
|
|
||||||
class Group(Document):
|
class Group(Document):
|
||||||
name = StringField()
|
name = StringField()
|
||||||
|
|
||||||
Group(name='test').save() # Saves in the default db
|
Group(name="test").save() # Saves in the default db
|
||||||
|
|
||||||
with switch_collection(Group, 'group2000') as Group:
|
with switch_collection(Group, 'group2000') as Group:
|
||||||
Group(name='hello Group 2000 collection!').save() # Saves in group2000 collection
|
Group(name="hello Group 2000 collection!").save() # Saves in group2000 collection
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. note:: Make sure any aliases have been registered with
|
.. note:: Make sure any aliases have been registered with
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
Installing MongoEngine
|
Installing MongoEngine
|
||||||
======================
|
======================
|
||||||
|
|
||||||
To use MongoEngine, you will need to download `MongoDB <http://mongodb.com/>`_
|
To use MongoEngine, you will need to download `MongoDB <http://mongodb.org/>`_
|
||||||
and ensure it is running in an accessible location. You will also need
|
and ensure it is running in an accessible location. You will also need
|
||||||
`PyMongo <http://api.mongodb.org/python>`_ to use MongoEngine, but if you
|
`PyMongo <http://api.mongodb.org/python>`_ to use MongoEngine, but if you
|
||||||
install MongoEngine using setuptools, then the dependencies will be handled for
|
install MongoEngine using setuptools, then the dependencies will be handled for
|
||||||
you.
|
you.
|
||||||
|
|
||||||
MongoEngine is available on PyPI, so you can use :program:`pip`:
|
MongoEngine is available on PyPI, so to use it you can use :program:`pip`:
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ Tutorial
|
|||||||
========
|
========
|
||||||
|
|
||||||
This tutorial introduces **MongoEngine** by means of example --- we will walk
|
This tutorial introduces **MongoEngine** by means of example --- we will walk
|
||||||
through how to create a simple **Tumblelog** application. A tumblelog is a
|
through how to create a simple **Tumblelog** application. A Tumblelog is a type
|
||||||
blog that supports mixed media content, including text, images, links, video,
|
of blog where posts are not constrained to being conventional text-based posts.
|
||||||
audio, etc. For simplicity's sake, we'll stick to text, image, and link
|
As well as text-based entries, users may post images, links, videos, etc. For
|
||||||
entries. As the purpose of this tutorial is to introduce MongoEngine, we'll
|
simplicity's sake, we'll stick to text, image and link entries in our
|
||||||
|
application. As the purpose of this tutorial is to introduce MongoEngine, we'll
|
||||||
focus on the data-modelling side of the application, leaving out a user
|
focus on the data-modelling side of the application, leaving out a user
|
||||||
interface.
|
interface.
|
||||||
|
|
||||||
@@ -15,14 +16,14 @@ Getting started
|
|||||||
|
|
||||||
Before we start, make sure that a copy of MongoDB is running in an accessible
|
Before we start, make sure that a copy of MongoDB is running in an accessible
|
||||||
location --- running it locally will be easier, but if that is not an option
|
location --- running it locally will be easier, but if that is not an option
|
||||||
then it may be run on a remote server. If you haven't installed MongoEngine,
|
then it may be run on a remote server. If you haven't installed mongoengine,
|
||||||
simply use pip to install it like so::
|
simply use pip to install it like so::
|
||||||
|
|
||||||
$ pip install mongoengine
|
$ pip install mongoengine
|
||||||
|
|
||||||
Before we can start using MongoEngine, we need to tell it how to connect to our
|
Before we can start using MongoEngine, we need to tell it how to connect to our
|
||||||
instance of :program:`mongod`. For this we use the :func:`~mongoengine.connect`
|
instance of :program:`mongod`. For this we use the :func:`~mongoengine.connect`
|
||||||
function. If running locally, the only argument we need to provide is the name
|
function. If running locally the only argument we need to provide is the name
|
||||||
of the MongoDB database to use::
|
of the MongoDB database to use::
|
||||||
|
|
||||||
from mongoengine import *
|
from mongoengine import *
|
||||||
@@ -38,8 +39,8 @@ Defining our documents
|
|||||||
MongoDB is *schemaless*, which means that no schema is enforced by the database
|
MongoDB is *schemaless*, which means that no schema is enforced by the database
|
||||||
--- we may add and remove fields however we want and MongoDB won't complain.
|
--- we may add and remove fields however we want and MongoDB won't complain.
|
||||||
This makes life a lot easier in many regards, especially when there is a change
|
This makes life a lot easier in many regards, especially when there is a change
|
||||||
to the data model. However, defining schemas for our documents can help to iron
|
to the data model. However, defining schemata for our documents can help to
|
||||||
out bugs involving incorrect types or missing fields, and also allow us to
|
iron out bugs involving incorrect types or missing fields, and also allow us to
|
||||||
define utility methods on our documents in the same way that traditional
|
define utility methods on our documents in the same way that traditional
|
||||||
:abbr:`ORMs (Object-Relational Mappers)` do.
|
:abbr:`ORMs (Object-Relational Mappers)` do.
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ using* the new fields we need to support video posts. This fits with the
|
|||||||
Object-Oriented principle of *inheritance* nicely. We can think of
|
Object-Oriented principle of *inheritance* nicely. We can think of
|
||||||
:class:`Post` as a base class, and :class:`TextPost`, :class:`ImagePost` and
|
:class:`Post` as a base class, and :class:`TextPost`, :class:`ImagePost` and
|
||||||
:class:`LinkPost` as subclasses of :class:`Post`. In fact, MongoEngine supports
|
:class:`LinkPost` as subclasses of :class:`Post`. In fact, MongoEngine supports
|
||||||
this kind of modeling out of the box --- all you need do is turn on inheritance
|
this kind of modelling out of the box --- all you need do is turn on inheritance
|
||||||
by setting :attr:`allow_inheritance` to True in the :attr:`meta`::
|
by setting :attr:`allow_inheritance` to True in the :attr:`meta`::
|
||||||
|
|
||||||
class Post(Document):
|
class Post(Document):
|
||||||
@@ -127,8 +128,8 @@ link table, we can just store a list of tags in each post. So, for both
|
|||||||
efficiency and simplicity's sake, we'll store the tags as strings directly
|
efficiency and simplicity's sake, we'll store the tags as strings directly
|
||||||
within the post, rather than storing references to tags in a separate
|
within the post, rather than storing references to tags in a separate
|
||||||
collection. Especially as tags are generally very short (often even shorter
|
collection. Especially as tags are generally very short (often even shorter
|
||||||
than a document's id), this denormalization won't impact the size of the
|
than a document's id), this denormalisation won't impact very strongly on the
|
||||||
database very strongly. Let's take a look at the code of our modified
|
size of our database. So let's take a look that the code our modified
|
||||||
:class:`Post` class::
|
:class:`Post` class::
|
||||||
|
|
||||||
class Post(Document):
|
class Post(Document):
|
||||||
@@ -140,7 +141,7 @@ The :class:`~mongoengine.fields.ListField` object that is used to define a Post'
|
|||||||
takes a field object as its first argument --- this means that you can have
|
takes a field object as its first argument --- this means that you can have
|
||||||
lists of any type of field (including lists).
|
lists of any type of field (including lists).
|
||||||
|
|
||||||
.. note:: We don't need to modify the specialized post types as they all
|
.. note:: We don't need to modify the specialised post types as they all
|
||||||
inherit from :class:`Post`.
|
inherit from :class:`Post`.
|
||||||
|
|
||||||
Comments
|
Comments
|
||||||
@@ -148,7 +149,7 @@ Comments
|
|||||||
|
|
||||||
A comment is typically associated with *one* post. In a relational database, to
|
A comment is typically associated with *one* post. In a relational database, to
|
||||||
display a post with its comments, we would have to retrieve the post from the
|
display a post with its comments, we would have to retrieve the post from the
|
||||||
database and then query the database again for the comments associated with the
|
database, then query the database again for the comments associated with the
|
||||||
post. This works, but there is no real reason to be storing the comments
|
post. This works, but there is no real reason to be storing the comments
|
||||||
separately from their associated posts, other than to work around the
|
separately from their associated posts, other than to work around the
|
||||||
relational model. Using MongoDB we can store the comments as a list of
|
relational model. Using MongoDB we can store the comments as a list of
|
||||||
@@ -218,8 +219,8 @@ Now that we've got our user in the database, let's add a couple of posts::
|
|||||||
post2.tags = ['mongoengine']
|
post2.tags = ['mongoengine']
|
||||||
post2.save()
|
post2.save()
|
||||||
|
|
||||||
.. note:: If you change a field on an object that has already been saved and
|
.. note:: If you change a field on a object that has already been saved, then
|
||||||
then call :meth:`save` again, the document will be updated.
|
call :meth:`save` again, the document will be updated.
|
||||||
|
|
||||||
Accessing our data
|
Accessing our data
|
||||||
==================
|
==================
|
||||||
@@ -231,17 +232,17 @@ used to access the documents in the database collection associated with that
|
|||||||
class. So let's see how we can get our posts' titles::
|
class. So let's see how we can get our posts' titles::
|
||||||
|
|
||||||
for post in Post.objects:
|
for post in Post.objects:
|
||||||
print(post.title)
|
print post.title
|
||||||
|
|
||||||
Retrieving type-specific information
|
Retrieving type-specific information
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
|
||||||
This will print the titles of our posts, one on each line. But what if we want
|
This will print the titles of our posts, one on each line. But What if we want
|
||||||
to access the type-specific data (link_url, content, etc.)? One way is simply
|
to access the type-specific data (link_url, content, etc.)? One way is simply
|
||||||
to use the :attr:`objects` attribute of a subclass of :class:`Post`::
|
to use the :attr:`objects` attribute of a subclass of :class:`Post`::
|
||||||
|
|
||||||
for post in TextPost.objects:
|
for post in TextPost.objects:
|
||||||
print(post.content)
|
print post.content
|
||||||
|
|
||||||
Using TextPost's :attr:`objects` attribute only returns documents that were
|
Using TextPost's :attr:`objects` attribute only returns documents that were
|
||||||
created using :class:`TextPost`. Actually, there is a more general rule here:
|
created using :class:`TextPost`. Actually, there is a more general rule here:
|
||||||
@@ -258,14 +259,16 @@ instances of :class:`Post` --- they were instances of the subclass of
|
|||||||
practice::
|
practice::
|
||||||
|
|
||||||
for post in Post.objects:
|
for post in Post.objects:
|
||||||
print(post.title)
|
print post.title
|
||||||
print('=' * len(post.title))
|
print '=' * len(post.title)
|
||||||
|
|
||||||
if isinstance(post, TextPost):
|
if isinstance(post, TextPost):
|
||||||
print(post.content)
|
print post.content
|
||||||
|
|
||||||
if isinstance(post, LinkPost):
|
if isinstance(post, LinkPost):
|
||||||
print('Link: {}'.format(post.link_url))
|
print 'Link:', post.link_url
|
||||||
|
|
||||||
|
print
|
||||||
|
|
||||||
This would print the title of each post, followed by the content if it was a
|
This would print the title of each post, followed by the content if it was a
|
||||||
text post, and "Link: <url>" if it was a link post.
|
text post, and "Link: <url>" if it was a link post.
|
||||||
@@ -280,7 +283,7 @@ your query. Let's adjust our query so that only posts with the tag "mongodb"
|
|||||||
are returned::
|
are returned::
|
||||||
|
|
||||||
for post in Post.objects(tags='mongodb'):
|
for post in Post.objects(tags='mongodb'):
|
||||||
print(post.title)
|
print post.title
|
||||||
|
|
||||||
There are also methods available on :class:`~mongoengine.queryset.QuerySet`
|
There are also methods available on :class:`~mongoengine.queryset.QuerySet`
|
||||||
objects that allow different results to be returned, for example, calling
|
objects that allow different results to be returned, for example, calling
|
||||||
@@ -289,11 +292,11 @@ the first matched by the query you provide. Aggregation functions may also be
|
|||||||
used on :class:`~mongoengine.queryset.QuerySet` objects::
|
used on :class:`~mongoengine.queryset.QuerySet` objects::
|
||||||
|
|
||||||
num_posts = Post.objects(tags='mongodb').count()
|
num_posts = Post.objects(tags='mongodb').count()
|
||||||
print('Found {} posts with tag "mongodb"'.format(num_posts))
|
print 'Found %d posts with tag "mongodb"' % num_posts
|
||||||
|
|
||||||
Learning more about MongoEngine
|
Learning more about mongoengine
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
If you got this far you've made a great start, so well done! The next step on
|
If you got this far you've made a great start, so well done! The next step on
|
||||||
your MongoEngine journey is the `full user guide <guide/index.html>`_, where
|
your mongoengine journey is the `full user guide <guide/index.html>`_, where you
|
||||||
you can learn in-depth about how to use MongoEngine and MongoDB.
|
can learn indepth about how to use mongoengine and mongodb.
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ class BaseQuerySet(object):
|
|||||||
|
|
||||||
.. versionadded:: 0.4
|
.. versionadded:: 0.4
|
||||||
"""
|
"""
|
||||||
return self._document(**kwargs).save(force_insert=True)
|
return self._document(**kwargs).save()
|
||||||
|
|
||||||
def first(self):
|
def first(self):
|
||||||
"""Retrieve the first object matching the query."""
|
"""Retrieve the first object matching the query."""
|
||||||
|
|||||||
@@ -412,6 +412,7 @@ class IndexesTest(unittest.TestCase):
|
|||||||
User.ensure_indexes()
|
User.ensure_indexes()
|
||||||
info = User.objects._collection.index_information()
|
info = User.objects._collection.index_information()
|
||||||
self.assertEqual(sorted(info.keys()), ['_cls_1_user_guid_1', '_id_'])
|
self.assertEqual(sorted(info.keys()), ['_cls_1_user_guid_1', '_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
|
||||||
@@ -433,6 +434,7 @@ class IndexesTest(unittest.TestCase):
|
|||||||
|
|
||||||
info = BlogPost.objects._collection.index_information()
|
info = BlogPost.objects._collection.index_information()
|
||||||
self.assertEqual(sorted(info.keys()), ['_id_', 'date.yr_-1'])
|
self.assertEqual(sorted(info.keys()), ['_id_', 'date.yr_-1'])
|
||||||
|
BlogPost.drop_collection()
|
||||||
|
|
||||||
def test_list_embedded_document_index(self):
|
def test_list_embedded_document_index(self):
|
||||||
"""Ensure list embedded documents can be indexed
|
"""Ensure list embedded documents can be indexed
|
||||||
@@ -459,6 +461,7 @@ class IndexesTest(unittest.TestCase):
|
|||||||
post1 = BlogPost(title="Embedded Indexes tests in place",
|
post1 = BlogPost(title="Embedded Indexes tests in place",
|
||||||
tags=[Tag(name="about"), Tag(name="time")])
|
tags=[Tag(name="about"), Tag(name="time")])
|
||||||
post1.save()
|
post1.save()
|
||||||
|
BlogPost.drop_collection()
|
||||||
|
|
||||||
def test_recursive_embedded_objects_dont_break_indexes(self):
|
def test_recursive_embedded_objects_dont_break_indexes(self):
|
||||||
|
|
||||||
@@ -619,6 +622,8 @@ class IndexesTest(unittest.TestCase):
|
|||||||
post3 = BlogPost(title='test3', date=Date(year=2010), slug='test')
|
post3 = BlogPost(title='test3', date=Date(year=2010), slug='test')
|
||||||
self.assertRaises(OperationError, post3.save)
|
self.assertRaises(OperationError, post3.save)
|
||||||
|
|
||||||
|
BlogPost.drop_collection()
|
||||||
|
|
||||||
def test_unique_embedded_document(self):
|
def test_unique_embedded_document(self):
|
||||||
"""Ensure that uniqueness constraints are applied to fields on embedded documents.
|
"""Ensure that uniqueness constraints are applied to fields on embedded documents.
|
||||||
"""
|
"""
|
||||||
@@ -646,6 +651,8 @@ class IndexesTest(unittest.TestCase):
|
|||||||
sub=SubDocument(year=2010, slug='test'))
|
sub=SubDocument(year=2010, slug='test'))
|
||||||
self.assertRaises(NotUniqueError, post3.save)
|
self.assertRaises(NotUniqueError, post3.save)
|
||||||
|
|
||||||
|
BlogPost.drop_collection()
|
||||||
|
|
||||||
def test_unique_embedded_document_in_list(self):
|
def test_unique_embedded_document_in_list(self):
|
||||||
"""
|
"""
|
||||||
Ensure that the uniqueness constraints are applied to fields in
|
Ensure that the uniqueness constraints are applied to fields in
|
||||||
@@ -676,6 +683,8 @@ class IndexesTest(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertRaises(NotUniqueError, post2.save)
|
self.assertRaises(NotUniqueError, post2.save)
|
||||||
|
|
||||||
|
BlogPost.drop_collection()
|
||||||
|
|
||||||
def test_unique_with_embedded_document_and_embedded_unique(self):
|
def test_unique_with_embedded_document_and_embedded_unique(self):
|
||||||
"""Ensure that uniqueness constraints are applied to fields on
|
"""Ensure that uniqueness constraints are applied to fields on
|
||||||
embedded documents. And work with unique_with as well.
|
embedded documents. And work with unique_with as well.
|
||||||
@@ -709,6 +718,8 @@ class IndexesTest(unittest.TestCase):
|
|||||||
sub=SubDocument(year=2009, slug='test-1'))
|
sub=SubDocument(year=2009, slug='test-1'))
|
||||||
self.assertRaises(NotUniqueError, post3.save)
|
self.assertRaises(NotUniqueError, post3.save)
|
||||||
|
|
||||||
|
BlogPost.drop_collection()
|
||||||
|
|
||||||
def test_ttl_indexes(self):
|
def test_ttl_indexes(self):
|
||||||
|
|
||||||
class Log(Document):
|
class Log(Document):
|
||||||
@@ -748,11 +759,13 @@ class IndexesTest(unittest.TestCase):
|
|||||||
raise AssertionError("We saved a dupe!")
|
raise AssertionError("We saved a dupe!")
|
||||||
except NotUniqueError:
|
except NotUniqueError:
|
||||||
pass
|
pass
|
||||||
|
Customer.drop_collection()
|
||||||
|
|
||||||
def test_unique_and_primary(self):
|
def test_unique_and_primary(self):
|
||||||
"""If you set a field as primary, then unexpected behaviour can occur.
|
"""If you set a field as primary, then unexpected behaviour can occur.
|
||||||
You won't create a duplicate but you will update an existing document.
|
You won't create a duplicate but you will update an existing document.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class User(Document):
|
class User(Document):
|
||||||
name = StringField(primary_key=True, unique=True)
|
name = StringField(primary_key=True, unique=True)
|
||||||
password = StringField()
|
password = StringField()
|
||||||
@@ -768,23 +781,8 @@ class IndexesTest(unittest.TestCase):
|
|||||||
self.assertEqual(User.objects.count(), 1)
|
self.assertEqual(User.objects.count(), 1)
|
||||||
self.assertEqual(User.objects.get().password, 'secret2')
|
self.assertEqual(User.objects.get().password, 'secret2')
|
||||||
|
|
||||||
def test_unique_and_primary_create(self):
|
|
||||||
"""Create a new record with a duplicate primary key
|
|
||||||
throws an exception
|
|
||||||
"""
|
|
||||||
class User(Document):
|
|
||||||
name = StringField(primary_key=True)
|
|
||||||
password = StringField()
|
|
||||||
|
|
||||||
User.drop_collection()
|
User.drop_collection()
|
||||||
|
|
||||||
User.objects.create(name='huangz', password='secret')
|
|
||||||
with self.assertRaises(NotUniqueError):
|
|
||||||
User.objects.create(name='huangz', password='secret2')
|
|
||||||
|
|
||||||
self.assertEqual(User.objects.count(), 1)
|
|
||||||
self.assertEqual(User.objects.get().password, 'secret')
|
|
||||||
|
|
||||||
def test_index_with_pk(self):
|
def test_index_with_pk(self):
|
||||||
"""Ensure you can use `pk` as part of a query"""
|
"""Ensure you can use `pk` as part of a query"""
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -198,6 +198,19 @@ class ConnectionTest(unittest.TestCase):
|
|||||||
self.assertTrue(isinstance(db, pymongo.database.Database))
|
self.assertTrue(isinstance(db, pymongo.database.Database))
|
||||||
self.assertEqual(db.name, 'test')
|
self.assertEqual(db.name, 'test')
|
||||||
|
|
||||||
|
def test_connect_uri_with_replicaset(self):
|
||||||
|
"""Ensure connect() works when specifying a replicaSet."""
|
||||||
|
if IS_PYMONGO_3:
|
||||||
|
c = connect(host='mongodb://localhost/test?replicaSet=local-rs')
|
||||||
|
db = get_db()
|
||||||
|
self.assertTrue(isinstance(db, pymongo.database.Database))
|
||||||
|
self.assertEqual(db.name, 'test')
|
||||||
|
else:
|
||||||
|
# PyMongo < v3.x raises an exception:
|
||||||
|
# "localhost:27017 is not a member of replica set local-rs"
|
||||||
|
with self.assertRaises(MongoEngineConnectionError):
|
||||||
|
c = connect(host='mongodb://localhost/test?replicaSet=local-rs')
|
||||||
|
|
||||||
def test_uri_without_credentials_doesnt_override_conn_settings(self):
|
def test_uri_without_credentials_doesnt_override_conn_settings(self):
|
||||||
"""Ensure connect() uses the username & password params if the URI
|
"""Ensure connect() uses the username & password params if the URI
|
||||||
doesn't explicitly specify them.
|
doesn't explicitly specify them.
|
||||||
@@ -319,38 +332,6 @@ class ConnectionTest(unittest.TestCase):
|
|||||||
self.assertEqual(dict(conn1.write_concern), {'w': 1, 'j': True})
|
self.assertEqual(dict(conn1.write_concern), {'w': 1, 'j': True})
|
||||||
self.assertEqual(dict(conn2.write_concern), {'w': 1, 'j': True})
|
self.assertEqual(dict(conn2.write_concern), {'w': 1, 'j': True})
|
||||||
|
|
||||||
def test_connect_with_replicaset_via_uri(self):
|
|
||||||
"""Ensure connect() works when specifying a replicaSet via the
|
|
||||||
MongoDB URI.
|
|
||||||
"""
|
|
||||||
if IS_PYMONGO_3:
|
|
||||||
c = connect(host='mongodb://localhost/test?replicaSet=local-rs')
|
|
||||||
db = get_db()
|
|
||||||
self.assertTrue(isinstance(db, pymongo.database.Database))
|
|
||||||
self.assertEqual(db.name, 'test')
|
|
||||||
else:
|
|
||||||
# PyMongo < v3.x raises an exception:
|
|
||||||
# "localhost:27017 is not a member of replica set local-rs"
|
|
||||||
with self.assertRaises(MongoEngineConnectionError):
|
|
||||||
c = connect(host='mongodb://localhost/test?replicaSet=local-rs')
|
|
||||||
|
|
||||||
def test_connect_with_replicaset_via_kwargs(self):
|
|
||||||
"""Ensure connect() works when specifying a replicaSet via the
|
|
||||||
connection kwargs
|
|
||||||
"""
|
|
||||||
if IS_PYMONGO_3:
|
|
||||||
c = connect(replicaset='local-rs')
|
|
||||||
self.assertEqual(c._MongoClient__options.replica_set_name,
|
|
||||||
'local-rs')
|
|
||||||
db = get_db()
|
|
||||||
self.assertTrue(isinstance(db, pymongo.database.Database))
|
|
||||||
self.assertEqual(db.name, 'test')
|
|
||||||
else:
|
|
||||||
# PyMongo < v3.x raises an exception:
|
|
||||||
# "localhost:27017 is not a member of replica set local-rs"
|
|
||||||
with self.assertRaises(MongoEngineConnectionError):
|
|
||||||
c = connect(replicaset='local-rs')
|
|
||||||
|
|
||||||
def test_datetime(self):
|
def test_datetime(self):
|
||||||
connect('mongoenginetest', tz_aware=True)
|
connect('mongoenginetest', tz_aware=True)
|
||||||
d = datetime.datetime(2010, 5, 5, tzinfo=utc)
|
d = datetime.datetime(2010, 5, 5, tzinfo=utc)
|
||||||
|
|||||||
Reference in New Issue
Block a user