摘要:接下来判断是否为空。因此接下来执行。这个方法用于获取字典中指定键名的键值第一个参数,如果该键名不存在,则返回第二个参数设定的默认值。当我们填写好表单,点击发布按钮,表单就以方式被提交到相对路径,对应的绝对路径为。
前面的话
在Demo1里面,我们练习了如何部署应用、tornado框架的基本结构以及应用如何处理请求。
其实Demo1算不上一个博客啦。一个最基本的信息系统一定要包含对数据库的增、删、改和查。所以这次,我们来将Demo1升级为Demo2,添加上基本的增删改查。
终于=。=在github上创建了项目,把源码传上去了。有需要的同学自己去下载吧。
https://github.com/cAntCheng/simple_tutorial_of_tornado
呐,还是把源码在这里贴一下
demo.py
#!/usr/bin/env python # -*- coding: utf-8 -*- import os.path import tornado.auth import tornado.escape import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web from tornado.options import define, options import pymongo define("port", default=8002, help="run on the given port", type=int) class Application(tornado.web.Application): def __init__(self): handlers = [ (r"/", MainHandler), (r"/edit/([0-9Xx-]+)", EditHandler), (r"/add", EditHandler), (r"/delete/([0-9Xx-]+)", DelHandler), (r"/blog/([0-9Xx-]+)", BlogHandler), ] settings = dict( template_path=os.path.join(os.path.dirname(__file__), "templates"), static_path=os.path.join(os.path.dirname(__file__), "static"), debug=True, ) conn = pymongo.Connection("localhost", 27017) self.db = conn["demo2"] tornado.web.Application.__init__(self, handlers, **settings) class MainHandler(tornado.web.RequestHandler): def get(self): import time coll = self.application.db.blog blogs = coll.find().sort("id",pymongo.DESCENDING) self.render( "index.html", blogs = blogs, time = time, ) class EditHandler(tornado.web.RequestHandler): def get(self, id=None): blog = dict() if id: coll = self.application.db.blog blog = coll.find_one({"id": int(id)}) self.render("edit.html", blog = blog) def post(self, id=None): import time coll = self.application.db.blog blog = dict() if id: blog = coll.find_one({"id": int(id)}) blog["title"] = self.get_argument("title", None) blog["content"] = self.get_argument("content", None) if id: coll.save(blog) else: last = coll.find().sort("id",pymongo.DESCENDING).limit(1) lastone = dict() for item in last: lastone = item blog["id"] = int(lastone["id"]) + 1 blog["date"] = int(time.time()) coll.insert(blog) self.redirect("/") class DelHandler(tornado.web.RequestHandler): def get(self, id=None): coll = self.application.db.blog if id: blog = coll.remove({"id": int(id)}) self.redirect("/") class BlogHandler(tornado.web.RequestHandler): def get(self, id=None): import time coll = self.application.db.blog if id: blog = coll.find_one({"id": int(id)}) self.render("blog.html", page_title = "我的博客", blog = blog, time = time, ) else: self.redirect("/") def main(): tornado.options.parse_command_line() http_server = tornado.httpserver.HTTPServer(Application()) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start() if __name__ == "__main__": main()
index.html
{% autoescape None %}B06 Innovation Space
blog.html
{% autoescape None %}{{ page_title }}
edit.html
B06 Innovation Space
代码回顾:
handlers = [ (r"/", MainHandler), (r"/edit/([0-9Xx-]+)", EditHandler), (r"/add", EditHandler), (r"/delete/([0-9Xx-]+)", DelHandler), (r"/blog/([0-9Xx-]+)", BlogHandler), ]
在Demo2中定义了5个handler,分别是
(r"/", MainHandler)->博客列表
(r"/edit/([0-9Xx-]+)", MainHandler)->编辑博客
(r"/add", MainHandler)->发表博客
(r"/delete/([0-9Xx-]+)", MainHandler)->删除博客
(r"/blog/([0-9Xx-]+)", MainHandler)->查看博客
通过这五个handler,我们终于能写出一个真正的博客了噢耶。
有没有注意到/([0-9Xx-]+)!!!这是干嘛的呢?恩,这是一个url参数。这个正则表达式规定参数由0-9的数字和X组成。
在edit、delete和blog方法中,我们需要一个博客id参数来找到指定的博客进行响应操作,所以我们在这里添加了一个url参数。
代码回顾:
class MainHandler(tornado.web.RequestHandler): def get(self): import time coll = self.application.db.blog blogs = coll.find().sort("id",pymongo.DESCENDING) self.render( "index.html", blogs = blogs, time = time, )
在MainHandler中,我们通过find()查询所有的博客,并通过sort("id",pymongo.DESCENDING)对博客id进行倒序排序(因为id越大,博文就越新,那它就应该在越前面显示嘛)。
同时载入了time模块,方便我们在模板里输出正确格式的时间。
代码回顾:
{{ time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(blog["date"]) ) }}
看看index.html,在输出时间的这一行,调用了time模块的strftime()方法,将在数据库储存的时间按照制定的格式%Y-%m-%d %H:%M:%S输出。
注意:可以看到,在self.render()方法中,我们将time对象作为参数传递到模板中。
这样我们才可以在模板中调用time对象的方法。
代码回顾:
{% for blog in blogs %} ... {% end %}
通过for循环输出博客列表。
来看看效果(不要在意里面乱七八糟的内容=。=):
代码回顾:
(r"/add", EditHandler),
有没有觉得奇怪=。=,为什么add(发表博客)调用的还是EditHandler。
解释:
一般的博客系统,发表博客和编辑博客的模板(html文件)其实是一样的。无非是编辑博客的模板里填充了博客的内容,而发表博客的模板是一个空表单。
因此我们常常把新增和编辑放在同一个方法里处理。具体的处理方法我们下面继续聊。
代码回顾:
class EditHandler(tornado.web.RequestHandler): def get(self, id=None): blog = dict() if id: coll = self.application.db.blog blog = coll.find_one({"id": int(id)}) self.render("edit.html", blog = blog)
在get方法中,我们新建了一个空字典blog。接下来判断id是否为空。我们通过判断id是否为空来选择下一步是编辑还是新增。
代码回顾:
思考一下业务逻辑,当我们点击首页发布按钮,即访问http://127.0.0.1:8002/add,由EditHandler执行get方法。
代码回顾:
def get(self, id=None):
因为没有传递url参数,所以id赋值为默认值None。
代码回顾:
if id: coll = self.application.db.blog blog = coll.find_one({"id": int(id)}) self.render("edit.html", blog = blog)
因为id = None,所以if id:为false。因此接下来执行self.render("edit.html",blog = blog)。
代码回顾:
{% if blog.get("id", None) %}
在edit.html中,我们通过判断blog.get("id", None)的值是否为None来输出不同的form标签。
dict.get("key","Defalt")这个方法用于获取字典中指定键名的键值(第一个参数),如果该键名不存在,则返回第二个参数设定的默认值。
要调用这个方法,我们必须有一个字典可以查找。所以在EditHandler的get方法中,我们定义了一个空字典:blog(还记得吗?回头看一下代码吧。)
继续刚才的业务逻辑,我们渲染了edit.html,并将空字典:blog作为参数传递到模板文件中。所以blog.get("id", None) == None,所以输出。
下面的{{ blog.get("title", "") }}和{{ blog.get("content", "") }},同上,均为空字符串。所以我们最终得到了一个空表单页面,也就是我们的发布博客页面。
当我们填写好表单,点击发布按钮,表单就以POST方式被提交到/add(相对路径,对应的绝对路径为http://127.0.0.1:8002/add)。这时候EditHandler执行post方法。
代码回顾:
def post(self, id=None): import time coll = self.application.db.blog blog = dict() if id: blog = coll.find_one({"id": int(id)}) blog["title"] = self.get_argument("title", None) blog["content"] = self.get_argument("content", None) if id: coll.save(blog) else: last = coll.find().sort("id",pymongo.DESCENDING).limit(1) lastone = dict() for item in last: lastone = item blog["id"] = int(lastone["id"]) + 1 blog["date"] = int(time.time()) coll.insert(blog) self.redirect("/")
在post方法中,同样的逻辑判断执行新增还是编辑。
代码回顾:
blog["title"] = self.get_argument("title", None) blog["content"] = self.get_argument("content", None)
将获取的表单填充到空字典:blog中,然后调用coll.insert(blog)方法向数据库中插入文档。
诶诶诶,等等,好像插入之前还有好几行啊!!
好吧=。=这几行代码是用来生成新博客id的。我们的博客需要一个id来标识身份,所以我们给每一篇博客设置一个id。一般就是用一个从1开始自增的整数作为id啦。
解释:
因为mongodb不像mysql那样可以设置自增字段,所以我们需要自己生成自增的id(查过资料应该是有办法设置自增,但是文档没太看明白=。=就当没有办法吧。除了文档中的办法,我查了好久,发现都是靠自己写函数生成自增的id,大家有兴趣可以自己去查一下。在这里我就用自己的方法了。)
我的方法是这样的:
last = coll.find().sort("id",pymongo.DESCENDING).limit(1)倒序查询数据库获取最后id最大的那一条记录。因为find()函数返回的结果是一个数组?所以要用for循环取值(因为只查询了一条记录,所以用一个循环也不会太奢侈吧啦啦啦)。
blog["id"] = int(lastone["id"]) + 1将最大id加1赋值给新博客的id。因为mongodb在存整型数的时候好像会默认存为浮点型(具体可以自行百度),所以用int()方法处理lastone["id"]保证我们处理过程中数据类型的正确。
好了,这样我们终于成功新增了一篇博客!!!
查当我们在首页点击某一篇博客的标题的时候,比如点击第二篇,我们会访问http://127.0.0.1:8002/blog/2,进入到这个页面:
这个过程是这样的:/blog对应BlogHandler,执行get方法。
代码回顾:
class BlogHandler(tornado.web.RequestHandler): def get(self, id=None): import time coll = self.application.db.blog if id: blog = coll.find_one({"id": int(id)}) self.render("blog.html", page_title = "我的博客", blog = blog, time = time, ) else: self.redirect("/")
if判断id是否存在,不存在则跳转到首页。我们这里get方法获取到url参数,因此id=2。blog = coll.find_one({"id": int(id)})查询该博客并渲染博客页面。
这样,我们就完成了博客查看的功能。
改留一个小问题。
因为这个demo是刚开始学tornado的时候写的,所以代码其实写得很糟糕。
BlogHandler可能这样写会更好一点,初学的同学看一看,思考一下为什么。我就不改demo里的代码了。class BlogHandler(tornado.web.RequestHandler): def get(self, id=0): import time coll = self.application.db.blog blog = coll.find_one({"id": int(id)}) if blog: self.render("blog.html", page_title = "我的博客", blog = blog, time = time, ) else: self.redirect("/")
代码回顾:
class EditHandler(tornado.web.RequestHandler): def get(self, id=None): blog = dict() if id: coll = self.application.db.blog blog = coll.find_one({"id": int(id)}) self.render("edit.html", blog = blog) def post(self, id=None): import time coll = self.application.db.blog blog = dict() if id: blog = coll.find_one({"id": int(id)}) blog["title"] = self.get_argument("title", None) blog["content"] = self.get_argument("content", None) if id: coll.save(blog) else: last = coll.find().sort("id",pymongo.DESCENDING).limit(1) lastone = dict() for item in last: lastone = item blog["id"] = int(lastone["id"]) + 1 blog["date"] = int(time.time()) coll.insert(blog) self.redirect("/")
自己看,就不多说了=。=
删删除操作的逻辑是,传递博客id给DelHandler,然后调用remove()方法从数据库删除指定博客。
代码回顾:
class DelHandler(tornado.web.RequestHandler): def get(self, id=None): coll = self.application.db.blog if id: blog = coll.remove({"id": int(id)}) self.redirect("/")
<( ̄ˇ ̄)/相信聪明的你已经看懂了!
总结至此,我们练习了mongodb的增删改查,也实现了应用的增删改查。
当然这个Demo还有很多需要改进的地方,比如:
构造形如http://127.0.0.1:8002/delete?id=2的链接,通过get方法传递参数。
给我们的表单加上格式验证。
同学们可以自己稍作修改尝试一下。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/18733.html
摘要:接下来判断是否为空。因此接下来执行。这个方法用于获取字典中指定键名的键值第一个参数,如果该键名不存在,则返回第二个参数设定的默认值。当我们填写好表单,点击发布按钮,表单就以方式被提交到相对路径,对应的绝对路径为。 前面的话 在Demo1里面,我们练习了如何部署应用、tornado框架的基本结构以及应用如何处理请求。 其实Demo1算不上一个博客啦。一个最基本的信息系统一定要包含对数据...
摘要:学习笔记七数学形态学关注的是图像中的形状,它提供了一些方法用于检测形状和改变形状。学习笔记十一尺度不变特征变换,简称是图像局部特征提取的现代方法基于区域图像块的分析。本文的目的是简明扼要地说明的编码机制,并给出一些建议。 showImg(https://segmentfault.com/img/bVRJbz?w=900&h=385); 前言 开始之前,我们先来看这样一个提问: pyth...
摘要:学的过程中查阅了无数资料,也收获了一些经验,所以希望总结出一份简易入门教程供初学者参考。完整的教程将尽可能遵循下面的目录顺序。安装的安装也很简单。搭建简单服务器表示不是必要的这里仅以做示范,其他系统操作方法类似。 前言: 这两天在学着用Python + Tornado +MongoDB来做Web开发(哈哈哈这个词好高端)。学的过程中查阅了无数资料,也收获了一些经验,所以希望总结出一份...
摘要:学的过程中查阅了无数资料,也收获了一些经验,所以希望总结出一份简易入门教程供初学者参考。完整的教程将尽可能遵循下面的目录顺序。安装的安装也很简单。搭建简单服务器表示不是必要的这里仅以做示范,其他系统操作方法类似。 前言: 这两天在学着用Python + Tornado +MongoDB来做Web开发(哈哈哈这个词好高端)。学的过程中查阅了无数资料,也收获了一些经验,所以希望总结出一份...
阅读 3205·2021-11-24 09:39
阅读 2872·2021-09-09 11:34
阅读 3169·2021-09-07 09:58
阅读 2275·2019-08-30 13:07
阅读 2827·2019-08-29 15:09
阅读 1542·2019-08-29 13:01
阅读 2282·2019-08-26 12:18
阅读 1865·2019-08-26 10:28