Tutorial updates
This commit is contained in:
parent
88f96b0838
commit
8a7b619b77
@ -74,9 +74,13 @@ to point across databases and collections. Below is an example schema, using
|
|||||||
Switch Database Context Manager
|
Switch Database Context Manager
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
Sometimes you might want to switch the database to query against for a class.
|
Sometimes you may want to switch the database to query against for a class,
|
||||||
|
for example, you archive older data into a separate database for performance
|
||||||
|
reasons.
|
||||||
|
|
||||||
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 class eg ::
|
you to change the database alias for a given class allowing quick and easy
|
||||||
|
access to the same User document across databases.eg ::
|
||||||
|
|
||||||
from mongoengine.context_managers import switch_db
|
from mongoengine.context_managers import switch_db
|
||||||
|
|
||||||
@ -87,3 +91,6 @@ you to change the database alias for a class eg ::
|
|||||||
|
|
||||||
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'
|
||||||
|
|
||||||
|
.. note:: Make sure any aliases have been registered with
|
||||||
|
:func:`~mongoengine.register_connection` before using the context manager.
|
||||||
|
@ -7,7 +7,7 @@ MongoDB. To install it, simply run
|
|||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
# pip install -U mongoengine
|
$ pip install -U mongoengine
|
||||||
|
|
||||||
:doc:`tutorial`
|
:doc:`tutorial`
|
||||||
Start here for a quick overview.
|
Start here for a quick overview.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
========
|
========
|
||||||
Tutorial
|
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 type
|
through how to create a simple **Tumblelog** application. A Tumblelog is a type
|
||||||
of blog where posts are not constrained to being conventional text-based posts.
|
of blog where posts are not constrained to being conventional text-based posts.
|
||||||
@ -12,23 +13,29 @@ interface.
|
|||||||
|
|
||||||
Getting started
|
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.
|
then it may be run on a remote server. If you haven't installed mongoengine,
|
||||||
|
simply use pip to install it like so::
|
||||||
|
|
||||||
|
$ 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. The only argument we need to provide is the name of the MongoDB
|
function. If running locally the only argument we need to provide is the name
|
||||||
database to use::
|
of the MongoDB database to use::
|
||||||
|
|
||||||
from mongoengine import *
|
from mongoengine import *
|
||||||
|
|
||||||
connect('tumblelog')
|
connect('tumblelog')
|
||||||
|
|
||||||
For more information about connecting to MongoDB see :ref:`guide-connecting`.
|
There are lots of options for connecting to MongoDB, for more information about
|
||||||
|
them see the :ref:`guide-connecting` guide.
|
||||||
|
|
||||||
Defining our documents
|
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
|
||||||
@ -39,17 +46,19 @@ define utility methods on our documents in the same way that traditional
|
|||||||
|
|
||||||
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
|
link posts to an individual. We also need to store our different types of
|
||||||
**posts** (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
|
||||||
specified 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 others are slightly more involved.
|
posts. We'll start with **users**, as the other document models are slightly
|
||||||
|
more involved.
|
||||||
|
|
||||||
Users
|
Users
|
||||||
-----
|
-----
|
||||||
|
|
||||||
Just as if we were using a relational database with an ORM, we need to define
|
Just as if we were using a relational database with an ORM, we need to define
|
||||||
which fields a :class:`User` may have, and what their types will be::
|
which fields a :class:`User` may have, and what types of data they might store::
|
||||||
|
|
||||||
class User(Document):
|
class User(Document):
|
||||||
email = StringField(required=True)
|
email = StringField(required=True)
|
||||||
@ -58,11 +67,13 @@ which fields a :class:`User` may have, and what their types will be::
|
|||||||
|
|
||||||
This looks similar to how a the structure of a table would be defined in a
|
This looks similar to how a the structure of a table would be defined in a
|
||||||
regular ORM. The key difference is that this schema will never be passed on to
|
regular ORM. The key difference is that this schema will never be passed on to
|
||||||
MongoDB --- this will only be enforced at the application level. Also, the User
|
MongoDB --- this will only be enforced at the application level, making future
|
||||||
documents will be stored in a MongoDB *collection* rather than a table.
|
changes easy to manage. Also, the User documents will be stored in a
|
||||||
|
MongoDB *collection* rather than a table.
|
||||||
|
|
||||||
Posts, Comments and Tags
|
Posts, Comments and Tags
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
Now we'll think about how to store the rest of the information. If we were
|
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
|
||||||
@ -75,16 +86,17 @@ of them stand out as particularly intuitive solutions.
|
|||||||
|
|
||||||
Posts
|
Posts
|
||||||
^^^^^
|
^^^^^
|
||||||
But MongoDB *isn't* a relational database, so we're not going to do it that
|
|
||||||
|
Happily mongoDB *isn't* a relational database, so we're not going to do it that
|
||||||
way. As it turns out, we can use MongoDB's schemaless nature to provide us with
|
way. As it turns out, we can use MongoDB's schemaless nature to provide us with
|
||||||
a much nicer solution. We will store all of the posts in *one collection* ---
|
a much nicer solution. We will store all of the posts in *one collection* and
|
||||||
each post type will just have the fields it needs. If we later want to add
|
each post type will only store the fields it needs. If we later want to add
|
||||||
video posts, we don't have to modify the collection at all, we just *start
|
video posts, we don't have to modify the collection at all, we just *start
|
||||||
using* the new fields we need to support video posts. This fits with the
|
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 modelling 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):
|
||||||
@ -109,6 +121,7 @@ when they are saved, and dereferenced when they are loaded.
|
|||||||
|
|
||||||
Tags
|
Tags
|
||||||
^^^^
|
^^^^
|
||||||
|
|
||||||
Now that we have our Post models figured out, how will we attach tags to them?
|
Now that we have our Post models figured out, how will we attach tags to them?
|
||||||
MongoDB allows us to store lists of items natively, so rather than having a
|
MongoDB allows us to store lists of items natively, so rather than having a
|
||||||
link table, we can just store a list of tags in each post. So, for both
|
link table, we can just store a list of tags in each post. So, for both
|
||||||
@ -126,11 +139,14 @@ size of our database. So let's take a look that the code our modified
|
|||||||
|
|
||||||
The :class:`~mongoengine.ListField` object that is used to define a Post's tags
|
The :class:`~mongoengine.ListField` object that is used to define a Post's tags
|
||||||
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). Note that we don't need to
|
lists of any type of field (including lists).
|
||||||
modify the specialised post types as they all inherit from :class:`Post`.
|
|
||||||
|
.. note:: We don't need to modify the specialised post types as they all
|
||||||
|
inherit from :class:`Post`.
|
||||||
|
|
||||||
Comments
|
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, then query the database again for the comments associated with the
|
database, then query the database again for the comments associated with the
|
||||||
@ -181,15 +197,15 @@ Now that we've defined how our documents will be structured, let's start adding
|
|||||||
some documents to the database. Firstly, we'll need to create a :class:`User`
|
some documents to the database. Firstly, we'll need to create a :class:`User`
|
||||||
object::
|
object::
|
||||||
|
|
||||||
john = User(email='jdoe@example.com', first_name='John', last_name='Doe')
|
ross = User(email='ross@example.com', first_name='Ross', last_name='Lawley').save()
|
||||||
john.save()
|
|
||||||
|
|
||||||
Note that we could have also defined our user using attribute syntax::
|
.. note::
|
||||||
|
We could have also defined our user using attribute syntax::
|
||||||
|
|
||||||
john = User(email='jdoe@example.com')
|
ross = User(email='ross@example.com')
|
||||||
john.first_name = 'John'
|
ross.first_name = 'Ross'
|
||||||
john.last_name = 'Doe'
|
ross.last_name = 'Lawley'
|
||||||
john.save()
|
ross.save()
|
||||||
|
|
||||||
Now that we've got our user in the database, let's add a couple of posts::
|
Now that we've got our user in the database, let's add a couple of posts::
|
||||||
|
|
||||||
@ -198,16 +214,17 @@ Now that we've got our user in the database, let's add a couple of posts::
|
|||||||
post1.tags = ['mongodb', 'mongoengine']
|
post1.tags = ['mongodb', 'mongoengine']
|
||||||
post1.save()
|
post1.save()
|
||||||
|
|
||||||
post2 = LinkPost(title='MongoEngine Documentation', author=john)
|
post2 = LinkPost(title='MongoEngine Documentation', author=ross)
|
||||||
post2.link_url = 'http://tractiondigital.com/labs/mongoengine/docs'
|
post2.link_url = 'http://docs.mongoengine.com/'
|
||||||
post2.tags = ['mongoengine']
|
post2.tags = ['mongoengine']
|
||||||
post2.save()
|
post2.save()
|
||||||
|
|
||||||
Note that if you change a field on a object that has already been saved, then
|
.. note:: If you change a field on a object that has already been saved, 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
|
||||||
==================
|
==================
|
||||||
|
|
||||||
So now we've got a couple of posts in our database, how do we display them?
|
So now we've got a couple of posts in our database, how do we display them?
|
||||||
Each document class (i.e. any class that inherits either directly or indirectly
|
Each document class (i.e. any class that inherits either directly or indirectly
|
||||||
from :class:`~mongoengine.Document`) has an :attr:`objects` attribute, which is
|
from :class:`~mongoengine.Document`) has an :attr:`objects` attribute, which is
|
||||||
@ -219,6 +236,7 @@ class. So let's see how we can get our posts' titles::
|
|||||||
|
|
||||||
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`::
|
||||||
@ -257,6 +275,7 @@ text post, and "Link: <url>" if it was a link post.
|
|||||||
|
|
||||||
Searching our posts by tag
|
Searching our posts by tag
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
The :attr:`objects` attribute of a :class:`~mongoengine.Document` is actually a
|
The :attr:`objects` attribute of a :class:`~mongoengine.Document` is actually a
|
||||||
:class:`~mongoengine.queryset.QuerySet` object. This lazily queries the
|
:class:`~mongoengine.queryset.QuerySet` object. This lazily queries the
|
||||||
database only when you need the data. It may also be filtered to narrow down
|
database only when you need the data. It may also be filtered to narrow down
|
||||||
@ -275,3 +294,9 @@ used on :class:`~mongoengine.queryset.QuerySet` objects::
|
|||||||
num_posts = Post.objects(tags='mongodb').count()
|
num_posts = Post.objects(tags='mongodb').count()
|
||||||
print 'Found %d posts with tag "mongodb"' % num_posts
|
print 'Found %d posts with tag "mongodb"' % num_posts
|
||||||
|
|
||||||
|
Learning more about mongoengine
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
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>`_, where you
|
||||||
|
can learn indepth about how to use mongoengine and mongodb.
|
Loading…
x
Reference in New Issue
Block a user