您的位置:首页 > 数据库 > Mongodb

结合使用 MongoDB 和 Django

2013-01-31 15:25 771 查看
转自:http://www.ibm.com/developerworks/cn/opensource/os-django-mongo/#resources

简介: Django 是一种 Python Web 框架,由对象关系映射器 (ORM)、后端控制器和模板系统组成。MongoDB 是一种面向文档的数据库(也称为 NoSQL 数据库),能有效地进行扩展并提供高性能。在本文中,我们将学习如何从 Python 调用 MongoDB(使用 MongoEngine),以及如何将它集成到
Django 项目中以代替内置的 ORM。本文还包括用来为 MongoDB 后端创建、读取和更新数据的样例 Web 界面。

Django 是在一个极为出色的模块化样式中得到应用的;替换一个基于 Django 的 Web 应用程序的不同组件非常简单。由于 NoSQL 目前较为常见,您可能想要尝试运行一个具有不同后端而非具有标准关系数据库(如 MySQL®)的应用程序。在本文中,您将初体验 MongoDB,包括如何使用 PyMongo 或 MongoEngine 在您的 Python 项目中调用它。接着,您将使用 Django 和 MongoEngine 创建一个可执行创建、读取、更新、删除 (CRUD) 操作的简单博客。

关于 NoSQL 数据库

根据 nosql-database.org,NoSQL 数据库是 “下一代数据库,主要具有以下几个要点:非关系型、分布式、开放源码和可水平伸缩”。面向文档的数据库 MongoDB 就是这种类型的数据库。

从一种新的角度来看,Django 1.3 包含了对 SQLite、MySQL、PostgreSQL 和 Oracle 的支持,但是并不包含对 MongoDB 的支持。不过,要添加对 MongoDB 的支持非常容易,但要以失去自动管理面板为代价。因此,您必须根据您的需要进行权衡。

回页首

MongoDB 简介

MongoDB 可以充当 JavaScript 解释器,因此数据库操作是通过 JavaScript 命令完成的。在您的机器上本地安装 MongoDB 后(参见参考资料),可以尝试使用 清单
1 中列出的一些命令。

清单 1. 您可以尝试对 MongoDB 使用的样例 JavaScript 命令

var x = "0";
x === 0;
typeof({});

您不必成为一名 JavaScript 专家之后才开始使用 MongoDB;这里提供几个有用的概念:

您可以使用对象字面量语法 (object literal syntax) 创建对象,换句话说,会使用两个花括号(如
var myCollection = {};
)。

您可以使用方括号(
[]
)来创建数组。

除了数字、布尔值、null 和未定义值以外,JavaScript 中的其他所有值都是一个对象。

如果您想要了解关于 JavaScript 其他特性的更多信息,比如原型的面向对象的编程 (OOP)、范围规则,及其函数式编程特性,请参阅参考资料

MongoDB 是一种无模式数据库,与关系型数据库完全相反。无模式数据库没有使用表格,而是使用由文档组成的集合。这些文档是使用对象字面量语法创建的,如 清单 2 所示。

清单 2. 文档创建示例

var person1 = {name:"John Doe", age:25};
var person2 = {name:"Jane Doe", age:26, dept: 115};

现在,请执行 清单 3 中所示的命令来创建一个新集合。

清单 3. 创建集合

db.employees.save(person1);
db.employees.save(person2);

由于 MongoDB 具有无模式特性,所以
person1
person2
不必具有相同的列类型,甚至不必拥有相同的列编号。并且,MongoDB 本身具有动态特性,所以它会创建 employees 而不是抛出一个错误。您可以通过
find()
方法检索文档。要获取
employees 中的所有文档,可以直接调用
find()
,无需使用任何参数,如 清单 4 所示。

清单 4. 一个简单的 MongoDB 查询

> db.employees.find();
// returns
[
{   "_id" : {   "$oid" : "4e363c4dcc93747e68055fa1"   },
"name" : "John Doe",   "age" : 25   },
{   "_id" : {   "$oid" : "4e363c53cc93747e68055fa2"   },
"name" : "Jane Doe",   "dept" : 115,   "age" : 26   }
]

注意,
_id
等效于一个主键。要运行具体的查询,则需要使用键/值对传递另一个对象来指示您所要查询的内容,如 清单 5 所示。

清单 5. 通过一个搜索参数进行查询

> db.employees.find({name: "John Doe"});
// returns
[
{   "_id" : {   "$oid" : "4e363c4dcc93747e68055fa1"   },
"name" : "John Doe",   "age" : 25   }
]

要查询年龄大于 25 岁的员工,请执行 清单 6 中的命令。

清单 6. 查询年龄大于 25 岁的员工

> db.employees.find({age:{'$gt':25}});
// returns
[
{   "_id" : {   "$oid" : "4e363c53cc93747e68055fa2"   },
"name" : "Jane Doe",   "dept" : 115,   "age" : 26   }
]

$gt
是一个特殊操作符,表示大于。表 1 列出了其他修饰符。

表 1. 可以对 MongoDB 使用的修饰符

修饰符描述
$gt大于
$lt小于
$gte大于或等于
$lte小于或等于
$in检查某个数组是否存在,类似于
'in'
SQL 操作符。
当然,您也可以使用
update()
方法更新记录。您可以更新整条记录,如 清单 7 所示。

清单 7. 更新整条记录

> db.employees.update({
name:"John Doe",  // Document to update
{name:"John Doe", age:27} // updated document
});

此外,您还可以使用
$set
操作符仅更新一个值,如 清单 8 所示。

清单 8. 仅更新记录中的一个值

> db.employees.update({name:"John Doe",
{ '$set': {age:27} }
});

要清空集合,可以调用
remove()
方法,无需使用任何参数。例如,如果您想要从 employees 集合中移除 John Doe,那么您可以执行 清单 9 所示的操作。

清单 9. 从 employees 集合中移除 John Doe

> db.employees.remove({"name":"John Doe"});
> db.employees.find();
// returns
[
{   "_id" : {   "$oid" : "4e363c53cc93747e68055fa2"   },   "name" : "Jane Doe",
"dept" : 115,   "age" : 26   }
]

此内容对于刚开始使用 MongoDB 的您来说已经足够了。当然,您可以继续浏览官方网站,该网站提供了简洁的、基于 Web 的交互式 mongodb 命令提示符,以及指南和官方文档。请参阅 参考资料

回页首

将 Django 与 MongoDB 集成

有几个从 Python 或 Django 访问 MongoDB 的选项。第一个选项是使用 Python 模块,即 PyMongo。清单 10 是一个简单的 PyMongo 会话,假设您已经安装了 MongoDB,并且已经拥有一个在端口上运行的实例。

清单 10. 样例 PyMongo 会话

from pymongo import Connection

databaseName = "sample_database"
connection = Connection()

db = connection[databaseName]
employees = db['employees']

person1 = { "name" : "John Doe",
"age" : 25, "dept": 101, "languages":["English","German","Japanese"] }

person2 = { "name" : "Jane Doe",
"age" : 27, "languages":["English","Spanish","French"] }

print "clearing"
employees.remove()

print "saving"
employees.save(person1)
employees.save(person2)

print "searching"
for e in employees.find():
print e["name"] + " " + unicode(e["languages"])

PyMongo 允许您同时运行多个数据库。要定义一个连接,只需将数据库名字传递给连接实例。在本例中,Python 词典代替了 JavaScript 对象字面量来创建新文档定义,而 Python 列表代替了 JavaScript 数组。
find
方法会返回一个您可以进行迭代的数据库游标对象。

语法的简易性使 MongoDB 命令行与包含 PyMongo 的运行命令之间的切换变得容易。例如,清单 11 展示了如何使用 PyMongo 运行一个查询。

清单 11. 使用 PyMongo 运行一个查询

for e in employees.find({"name":"John Doe"}):
print e

您从 Python 调用 MongoDB 的另一个选项是 MongoEngine,如果您使用过 Django 的内置 ORM,那么您对此应该感到非常熟悉。MongoEngine 是一个文档到对象的映射器,从概念上说,它与映射到 ORM 的映射器类似。清单 12 显示了一个使用
MongoEngine 的示例会话。

清单 12. MongoEngine 示例会话

from mongoengine import *

connect('employeeDB')

class Employee(Document):
name = StringField(max_length=50)
age = IntField(required=False)

john = Employee(name="John Doe", age=25)
john.save()

jane = Employee(name="Jane Doe", age=27)
jane.save()

for e in Employee.objects.all():
print e["id"], e["name"], e["age"]

Employee
对象继承自
mongoengine.Document
。在本示例中,使用了两种字段类型:
StringField
IntField
。与
Django 的 ORM 相似,要通过查询获得集合中的所有文档,请调用
Employee.objects.all()
。请注意,要访问惟一的对象 ID,请使用
"id"
而非
"_id"


回页首

一个样例博客

现在要创建一个名为 Blongo 的简单博客。您将使用 Python 1.7、Django 1.3、MongoDB 1.8.2、MongoEngine 0.4 和 Hypertext Markup Language (HTML) 5。如果您想要重现我的精确设置,我习惯使用 Ubuntu Linux 和 FireFox。Blongo 在网页加载后就会显示所输入的所有博客条目,并且允许对任何条目执行更新和删除操作,换句话说,允许进行所有的标准 CRUD 操作。Django 视图拥有三个方法:
index
update
delete


层叠样式表 (CSS) 定义被引入一个单独的静态文件。相关内容我不想在此处赘述,您可以随意浏览 下载 部分中包含的源代码。

假设已安装好所需的所有工具,并且这些组件都能良好运行,那么请创建一个新的 Django 项目和必要的组件,如 清单 13 所示。

清单 13. 创建 Django 博客项目的命令

$ django-admin.py startproject blongo
$ cd blongo
$ django-admin.py startapp blogapp
$ mkdir templates
$ cd blogapp
$ mkdir static

Django 1.3 的新增内容是一个已包含在 Django 中的贡献型应用程序,可使用它来改进静态文件的处理。通过向任何应用程序目录添加一个静态目录(例如,本例中的 blogapp)并确保 django.contrib.staticfiles 包含在已安装应用程序中,Django 可以查找到诸如 .css 和 .js 的静态文件,而无需使用其他任何方法。清单
14 显示了设置文件的代码行,这些代码行已经进行了相应修改(来自默认的 settings.py 文件),使博客应用程序能够正常运行。

清单 14. 已改变的设置文件代码行(来自默认的 settings.py 文件)

# Django settings for blog project.
import os
APP_DIR = os.path.dirname( globals()['__file__'] )

DBNAME = 'blog'

TEMPLATE_DIRS = (
os.path.join( APP_DIR, 'templates' )
)

INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog.blogapp',
)

本项目中也有三个模板:index.html、update.html 和 delete.html。清单 15 显示了这三个模板文件的代码。

清单 15. index.html、update.html 和 delete.html 模板文件的代码

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<link href="{{STATIC_URL}}blog.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>Blongo</h1>
<form method="post" action="http://127.0.0.1:8000/">
{% csrf_token %}
<ul>
<li>
<input type="text" name="title" placeholder="Post Title" required>
</li>
<li>
<textarea name="content" placeholder="Enter Content" rows=5 cols=50 required>
</textarea>
</li>
<li>
<input type="submit" value="Add Post">
</li>
</ul>
</form>
<!-- Cycle through entries -->
{% for post in Posts %}
<h2> {{ post.title }} </h2>
<p>{{ post.last_update }}</p>
<p>{{ post.content }}</p>
<form method="get" action="http://127.0.0.1:8000/update">
<input type="hidden" name="id" value="{{ post.id }}">
<input type="hidden" name="title" value="{{ post.title }}">
<input type="hidden" name="last_update" value="{{ post.last_update }}">
<input type="hidden" name="content" value="{{ post.content }}">
<input type="submit" name="" value="update">
</form>
<form method="get" action="http://127.0.0.1:8000/delete">
<input type="hidden" name="id" value="{{post.id}}">
<input type="submit" value="delete">
</form>
{% endfor %}
</body>
</html>

<!-- update.html -->
<!DOCTYPE html>
<html>
<head>
<link href="{{STATIC_URL}}blog.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>Blongo - Update Entry</h1>
<form method="post" action="http://127.0.0.1:8000/update/">
{% csrf_token %}
<ul>
<li><input type="hidden" name="id" value="{{post.id}}"></li>
<li>
<input type="text" name="title" placeholder="Post Title"
value="{{post.title}}" required>
<input type="text" name="last_update"
value="{{post.last_update}}" required>
</li>
<li>
<textarea name="content" placeholder="Enter Content"
rows=5 cols=50 required>
{{post.content}}
</textarea>
</li>
<li>
<input type="submit" value="Save Changes">
</li>
</ul>
</form>
</body>
</html>
<!-- delete.html -->
<!DOCTYPE html>
<html>
<head>
<link href="{{STATIC_URL}}blog.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>Blongo - Delete Entry</h1>
<form method="post" action="http://127.0.0.1:8000/delete/">
{% csrf_token %}
<input type="hidden" name="id" value="{{id}}">
<p>Are you sure you want to delete this post?</p>
<input type="submit" value="Delete">
</form>
</body>
</html>

接着,更改 清单 16 中所示代码的 URL 映射,该映射指向索引、更新和删除的视图。您可能想让样例博客创建新的博客条目(在索引中)、更新现有博客帖子,并在想要删除这些帖子的时候删除它们。每个操作都是通过向特定 URL 发送一个请求来完成的。

清单 16. 索引、更新和删除的映射

from django.conf.urls.defaults import patterns, include, url

urlpatterns = patterns('',
url(r'^$', 'blog.blogapp.views.index'),
url(r'^update/', 'blog.blogapp.views.update'),
url(r'^delete/', 'blog.blogapp.views.delete'),
)

注意,您无 需运行
syncdb
Django 命令。要将 MongoDB 集成到您的应用程序中,只需使用 MongoEngine 即可。在 blogapp 目录的 models.py 文件中,添加 清单
17 中所示的代码。

清单 17. 在数据层中包含 MongoEngine

from mongoengine import *
from blog.settings import DBNAME

connect(DBNAME)

class Post(Document):
title = StringField(max_length=120, required=True)
content = StringField(max_length=500, required=True)
last_update = DateTimeField(required=True)

数据库名称是源自设置文件,用于分隔关注点。每个博客帖子都包含三个必要的字段:
title
content
last_update
。如果您将此清单与您通常在 Django 获得的清单进行对比,就会发现它们差别并不大。此清单使用了
mongoengine.Document
类,而非从
django.db.models.Model 中继承的类。在这里,我并不打算深入探讨数据类型之间的差别,但您可以随意查看 MongoEngine 文档(参见 参考资料)。

表 2 列出了 MongoEngine 字段类型,并显示了对等的 Django ORM 字段类型(如果存在的话)。

表 2. MongoEngine 字段类型和 Django ORM 对等物

MongoEngine 字段类型Django ORM 对等物
StringFieldCharField
URLFieldURLField
EmailFieldEmailField
IntFieldIntegerField
FloatFieldFloatField
DecimalFieldDecimalField
BooleanFieldBooleanField
DateTimeFieldDateTimeField
EmbeddedDocumentFieldNone
DictFieldNone
ListFieldNone
SortedListFieldNone
BinaryFieldNone
ObjectIdFieldNone
FileFieldFileField
最后,您可以创建自己的视图。在这里,您拥有三个视图方法:
index
update
delete
。要执行想要执行的操作,则必须向特定 URL 发送一个请求。例如,要更新一个文档,则必须向 localhost:8000/update
发送一个请求。执行一个 http 'GET' 请求不会执行保存、更新等操作。新博客帖子是从索引视图插入的。清单 18 显示了索引、更新和删除视图的实现。

清单 18. Django 视图

from django.shortcuts import render_to_response
from django.template import RequestContext
from models import Post
import datetime

def index(request):
if request.method == 'POST':
# save new post
title = request.POST['title']
content = request.POST['content']

post = Post(title=title)
post.last_update = datetime.datetime.now()
post.content = content
post.save()

# Get all posts from DB
posts = Post.objects
return render_to_response('index.html', {'Posts': posts},
context_instance=RequestContext(request))

def update(request):
id = eval("request." + request.method + "['id']")
post = Post.objects(id=id)[0]

if request.method == 'POST':
# update field values and save to mongo
post.title = request.POST['title']
post.last_update = datetime.datetime.now()
post.content = request.POST['content']
post.save()
template = 'index.html'
params = {'Posts': Post.objects}

elif request.method == 'GET':
template = 'update.html'
params = {'post':post}

return render_to_response(template, params, context_instance=RequestContext(request))

def delete(request):
id = eval("request." + request.method + "['id']")

if request.method == 'POST':
post = Post.objects(id=id)[0]
post.delete()
template = 'index.html'
params = {'Posts': Post.objects}
elif request.method == 'GET':
template = 'delete.html'
params = { 'id': id }

return render_to_response(template, params, context_instance=RequestContext(request))

您可能已经注意到用来索引文档 ID 的
eval
语句。使用该语句是为了避免编写 清单 19 中所示的
if
语句。

清单 19. 检索文档 ID 的替代方法

if request.method == 'POST':
id = request.POST['id']
elif request.method == 'GET':
id = request.GET['id']

您也可以这样编写代码。以上就是创建并运行一个简单博客需要执行的所有操作。显然,最终产品中还会添加许多组件,比如用户、登录、标签等。

结束语

正如您所看到的,从 Django 调用 MongoDB 真的不是很复杂。在本文中,我简单介绍了一下 MongoDB,并解释了如何访问它,以及如何通过 PyMongo 包装器和 MongoEngine 的 “对象至文档” 映射器,从 Python 操作 MongoDB 的集合和文档。最后,我快速演示了如何使用 Django 执行基础 CRUD 操作。虽然这只是第一步,但是希望您现在能够了解如何将此设置应用到您自己的项目中。

回页首

下载
描述名字大小下载方法
使用 MongoEngine 的 Django 应用程序样例blongo.zip12KBHTTP
关于下载方法的信息

参考资料

学习

从 Mozilla 提供的教程 "A re-introduction to JavaScript" 和 Douglas Crockford 撰写的书籍 JavaScript:
The Good Parts(O'Reilly Media/Yahoo Press,2008 年 5 月)中了解关于 JavaScript 的更多内容。

关注 Twitter 上的 developerWorks

观看 developerWorks 演示中心,从初学者的产品安装和配置演示,到面向有经验开发人员的高级功能。

随时关注 developerWorks 技术活动网络广播

访问 developerWorks Open source 专区获得丰富的 how-to 信息、工具和项目更新以及最受欢迎的文章和教程,帮助您用开放源码技术进行开发,并将它们与
IBM 产品结合使用。

获得产品和技术

了解并下载 MongoDB

下载并探索 Django

访问 Python 网站获取相关的下载和文档。

查看 MongoEngine

深入讨论 PyMongo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: