tutorial tweaks: better copy + use py3-friendly syntax
This commit is contained in:
parent
2bedb36d7f
commit
627cf90de0
@ -3,11 +3,10 @@ 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
|
||||||
of blog where posts are not constrained to being conventional text-based posts.
|
blog that supports mixed media content, including text, images, links, video,
|
||||||
As well as text-based entries, users may post images, links, videos, etc. For
|
audio, etc. For simplicity's sake, we'll stick to text, image, and link
|
||||||
simplicity's sake, we'll stick to text, image and link entries in our
|
entries. As the purpose of this tutorial is to introduce MongoEngine, we'll
|
||||||
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.
|
||||||
|
|
||||||
@ -16,14 +15,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 *
|
||||||
@ -39,18 +38,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 schemata for our documents can help to
|
to the data model. However, defining schemas for our documents can help to iron
|
||||||
iron out bugs involving incorrect types or missing fields, and also allow us to
|
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.
|
||||||
|
|
||||||
@ -78,7 +77,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
|
||||||
@ -96,7 +95,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 modelling out of the box --- all you need do is turn on inheritance
|
this kind of modeling 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):
|
||||||
@ -128,8 +127,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 denormalisation won't impact very strongly on the
|
than a document's id), this denormalization won't impact the size of the
|
||||||
size of our database. So let's take a look that the code our modified
|
database very strongly. Let's take a look at the code of our modified
|
||||||
:class:`Post` class::
|
:class:`Post` class::
|
||||||
|
|
||||||
class Post(Document):
|
class Post(Document):
|
||||||
@ -141,7 +140,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 specialised post types as they all
|
.. note:: We don't need to modify the specialized post types as they all
|
||||||
inherit from :class:`Post`.
|
inherit from :class:`Post`.
|
||||||
|
|
||||||
Comments
|
Comments
|
||||||
@ -149,7 +148,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, then query the database again for the comments associated with the
|
database and 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
|
||||||
@ -219,8 +218,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 a object that has already been saved, then
|
.. note:: If you change a field on an object that has already been saved and
|
||||||
call :meth:`save` again, the document will be updated.
|
then call :meth:`save` again, the document will be updated.
|
||||||
|
|
||||||
Accessing our data
|
Accessing our data
|
||||||
==================
|
==================
|
||||||
@ -232,17 +231,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:
|
||||||
@ -259,16 +258,14 @@ 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:', post.link_url
|
print('Link: {}'.format(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.
|
||||||
@ -283,7 +280,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
|
||||||
@ -292,11 +289,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 %d posts with tag "mongodb"' % num_posts
|
print('Found {} posts with tag "mongodb"'.format(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 you
|
your MongoEngine journey is the `full user guide <guide/index.html>`_, where
|
||||||
can learn indepth about how to use mongoengine and mongodb.
|
you can learn in-depth about how to use MongoEngine and MongoDB.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user