Compare commits

..

35 Commits

Author SHA1 Message Date
Stefan Wojcik
2626eca58e more readme tweaks [ci skip] 2017-02-26 13:38:39 -05:00
Stefan Wojcik
d5b1914158 include supported mongodb ver info in the readme [ci skip] 2017-02-26 13:35:03 -05:00
Stefan Wojcik
e20a34857d fix py3 2017-02-26 12:11:21 -05:00
Stefan Wojcik
7d0b533920 nicer ver decorators + only test $minDistance in v3.0 2017-02-26 11:59:22 -05:00
Stefan Wojcik
6a9e02635d refactor poorly isolated geo unit tests 2017-02-26 11:23:27 -05:00
Stefan Wojcik
5a1fdadf8b pymongo v2.7 doesn't support MongoDB v3.0 2017-02-26 03:13:58 -05:00
Stefan Wojcik
70871f671a fix version comparison 2017-02-26 02:48:35 -05:00
Stefan Wojcik
e6821d8656 flake8 debug 2017-02-26 02:45:37 -05:00
Stefan Wojcik
4f85547333 fix package name 2017-02-26 02:35:50 -05:00
Stefan Wojcik
deeb6d026d fix the $max operator 2017-02-26 02:29:59 -05:00
Stefan Wojcik
97d9a7cf43 different approach to running flake8 2017-02-26 02:29:21 -05:00
Stefan Wojcik
7850e47bf7 fix the $max operator 2017-02-26 02:24:48 -05:00
Stefan Wojcik
a94ec06275 fix authSource test 2017-02-26 02:21:25 -05:00
Stefan Wojcik
4acd7a5b75 skip older mongodb decorator 2017-02-26 02:14:34 -05:00
Stefan Wojcik
e6dcb39036 revert aggregate change 2017-02-25 22:54:19 -05:00
Stefan Wojcik
4ed65f8589 skip $minDistance for older MongoDB vers 2017-02-25 22:52:35 -05:00
Stefan Wojcik
39586e83cd pymongo v2.7 doesn't support MongoDB v3.0 2017-02-25 22:11:15 -05:00
Stefan Wojcik
5992fdd408 remove debug statement 2017-02-25 20:58:04 -05:00
Stefan Wojcik
70faaf445e fix queryset tests in mongodb v2.4 2017-02-25 20:55:59 -05:00
Stefan Wojcik
71ccfeac3c get_mongodb_version tests helper + fix indexing tests in mongodb v2.4 2017-02-25 20:21:20 -05:00
Stefan Wojcik
d39f5197cb tox.init cleanup 2017-02-25 19:10:00 -05:00
Stefan Wojcik
5b4eb02683 shuffle some jobs, focus on testing py27 and py35 2017-02-25 19:07:32 -05:00
Stefan Wojcik
d0442d7578 mongo v2.4 needs explicit service start 2017-02-25 18:48:59 -05:00
Stefan Wojcik
098a90ee96 no need for service start 2017-02-25 18:32:08 -05:00
Stefan Wojcik
d7d48e4c21 fix .travis.yml 2017-02-25 18:25:26 -05:00
Stefan Wojcik
cb62b457bc fix mongo install script 2017-02-25 18:21:04 -05:00
Stefan Wojcik
d29c1c1094 missing file 2017-02-25 18:17:53 -05:00
Stefan Wojcik
d6af8cb157 fix .travis.yml 2017-02-25 18:15:28 -05:00
Stefan Wojcik
8e2e5f506d customize the matrix + separate script to install mongodb 2017-02-25 18:11:21 -05:00
Stefan Wojcik
0ea1dfddaa merge latest master + test pymongo v2.8 instead of v2.9 + drop dev pymongo + smarter pypi deployment 2017-02-25 16:54:46 -05:00
Omer Katz
ce7142eb4f Fix the repo entry for MongoDB 3. 2015-07-17 21:53:06 +03:00
Omer Katz
5e17fc6d47 Only start mongodb if it's not started already after installation. 2015-07-17 21:46:31 +03:00
Omer Katz
ee7bd1bdae Start MongoDB if it's stopped. 2015-07-17 21:32:55 +03:00
Omer Katz
d75dc02614 Fixed the repos entry. 2015-07-17 21:25:12 +03:00
Omer Katz
c08ee77041 Test against multiple MongoDB versions. 2015-07-17 21:21:09 +03:00
8 changed files with 745 additions and 687 deletions

1
.gitignore vendored
View File

@@ -17,4 +17,3 @@ tests/test_bugfix.py
htmlcov/ htmlcov/
venv venv
venv3 venv3
scratchpad

View File

@@ -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

View File

@@ -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

View File

@@ -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,18 +39,18 @@ 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.
In our Tumblelog application we need to store several different types of In our Tumblelog application we need to store several different types of
information. We will need to have a collection of **users**, so that we may information. We will need to have a collection of **users**, so that we may
link posts to an individual. We also need to store our different types of link posts to an individual. We also need to store our different types of
**posts** (eg: text, image and link) in the database. To aid navigation of our **posts** (eg: text, image and link) in the database. To aid navigation of our
Tumblelog, posts may have **tags** associated with them, so that the list of Tumblelog, posts may have **tags** associated with them, so that the list of
posts shown to the user may be limited to posts that have been assigned a posts shown to the user may be limited to posts that have been assigned a
specific tag. Finally, it would be nice if **comments** could be added to specific tag. Finally, it would be nice if **comments** could be added to
posts. We'll start with **users**, as the other document models are slightly posts. We'll start with **users**, as the other document models are slightly
more involved. more involved.
@@ -77,7 +78,7 @@ Now we'll think about how to store the rest of the information. If we were
using a relational database, we would most likely have a table of **posts**, a using a relational database, we would most likely have a table of **posts**, a
table of **comments** and a table of **tags**. To associate the comments with table of **comments** and a table of **tags**. To associate the comments with
individual posts, we would put a column in the comments table that contained a individual posts, we would put a column in the comments table that contained a
foreign key to the posts table. We'd also need a link table to provide the foreign key to the posts table. We'd also need a link table to provide the
many-to-many relationship between posts and tags. Then we'd need to address the many-to-many relationship between posts and tags. Then we'd need to address the
problem of storing the specialised post-types (text, image and link). There are problem of storing the specialised post-types (text, image and link). There are
several ways we can achieve this, but each of them have their problems --- none several ways we can achieve this, but each of them have their problems --- none
@@ -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.

View File

@@ -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."""

View File

@@ -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

View File

@@ -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)