tutorial tweaks: better copy + use py3-friendly syntax

This commit is contained in:
Stefan Wojcik 2017-02-26 20:30:37 -05:00
parent 2bedb36d7f
commit 627cf90de0

View File

@ -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,8 +38,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 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.
@ -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.