From 627cf90de03dac4c172624b0c5571379589edaf7 Mon Sep 17 00:00:00 2001 From: Stefan Wojcik Date: Sun, 26 Feb 2017 20:30:37 -0500 Subject: [PATCH] tutorial tweaks: better copy + use py3-friendly syntax --- docs/tutorial.rst | 65 ++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 311d2888..fc92ce0c 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -3,11 +3,10 @@ Tutorial ======== This tutorial introduces **MongoEngine** by means of example --- we will walk -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. -As well as text-based entries, users may post images, links, videos, etc. For -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 +through how to create a simple **Tumblelog** application. A tumblelog is a +blog that supports mixed media content, including text, images, links, video, +audio, etc. For simplicity's sake, we'll stick to text, image, and link +entries. 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 interface. @@ -16,14 +15,14 @@ Getting started 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 -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:: $ pip install mongoengine 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` -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:: from mongoengine import * @@ -39,18 +38,18 @@ Defining our documents 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. 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 -iron out bugs involving incorrect types or missing fields, and also allow us to +to the data model. However, defining schemas for our documents can help 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 :abbr:`ORMs (Object-Relational Mappers)` do. 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 **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 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 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 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 -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 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 @@ -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 :class:`Post` as a base class, and :class:`TextPost`, :class:`ImagePost` and :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`:: 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 within the post, rather than storing references to tags in a separate 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 -size of our database. So let's take a look that the code our modified +than a document's id), this denormalization won't impact the size of the +database very strongly. Let's take a look at the code of our modified :class:`Post` class:: 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 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`. Comments @@ -149,7 +148,7 @@ Comments 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 -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 separately from their associated posts, other than to work around the 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.save() -.. note:: If you change a field on a object that has already been saved, then - call :meth:`save` again, the document will be updated. +.. note:: If you change a field on an object that has already been saved and + then call :meth:`save` again, the document will be updated. 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:: for post in Post.objects: - print post.title + print(post.title) 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 use the :attr:`objects` attribute of a subclass of :class:`Post`:: for post in TextPost.objects: - print post.content + print(post.content) Using TextPost's :attr:`objects` attribute only returns documents that were 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:: for post in Post.objects: - print post.title - print '=' * len(post.title) + print(post.title) + print('=' * len(post.title)) if isinstance(post, TextPost): - print post.content + print(post.content) if isinstance(post, LinkPost): - print 'Link:', post.link_url - - print + print('Link: {}'.format(post.link_url)) This would print the title of each post, followed by the content if it was a text post, and "Link: " 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:: for post in Post.objects(tags='mongodb'): - print post.title + print(post.title) There are also methods available on :class:`~mongoengine.queryset.QuerySet` 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:: 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 -your mongoengine journey is the `full user guide `_, where you -can learn indepth about how to use mongoengine and mongodb. +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 `_, where +you can learn in-depth about how to use MongoEngine and MongoDB.