tornado框架blog模块分析与使用


Posted in Python onNovember 21, 2013
#!/usr/bin/env python
#
# Copyright 2009 Facebook
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import markdown
import os.path
import re
import torndb
import tornado.auth
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import unicodedata
from tornado.options import define, options
#定义一些通用的配置信息,比如数据库的连接信息,端口信息
define("port", default=8888, help="run on the given port", type=int)
define("mysql_host", default="127.0.0.1:3306", help="blog database host")
define("mysql_database", default="blog", help="blog database name")
define("mysql_user", default="root", help="blog database user")
define("mysql_password", default="sa123", help="blog database password")
#定义Application信息,它是继承tornado.web.Application 的
class Application(tornado.web.Application):

 # __init__ 函数自动调用
    def __init__(self):

    #这里就是url对应的控制器,下面分别对应一个类,来处理里面的逻辑
        handlers = [
            (r"/", HomeHandler),
            (r"/archive", ArchiveHandler),
            (r"/feed", FeedHandler),
            (r"/entry/([^/]+)", EntryHandler),
            (r"/compose", ComposeHandler),
            (r"/auth/login", AuthLoginHandler),
            (r"/auth/logout", AuthLogoutHandler),
        ]

    #设置,如博客标题,模板目录,静态文件目录,xsrf,是否调试
        settings = dict(
            blog_title=u"Tornado Blog",
            template_path=os.path.join(os.path.dirname(__file__), "templates"),
            static_path=os.path.join(os.path.dirname(__file__), "static"),
            ui_modules={"Entry": EntryModule},
            xsrf_cookies=True,
            cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
            login_url="/auth/login",
            debug=True,
        )

     #然后调用tornado.web.Application类的__init__函数加载进来
        tornado.web.Application.__init__(self, handlers, **settings)
        # Have one global connection to the blog DB across all handlers

     #数据库连接信息
        self.db = torndb.Connection(
            host=options.mysql_host, database=options.mysql_database,
            user=options.mysql_user, password=options.mysql_password)
#基类,继承自tornado.web.RequestHandler 的,后面的类都是继承这个类的
class BaseHandler(tornado.web.RequestHandler):

#属性装饰器,使db函数变成一个属性,便于后面直接使用
    @property
    def db(self):
        return self.application.db

#获得当前的用户
    def get_current_user(self):
        user_id = self.get_secure_cookie("blogdemo_user")
        if not user_id: return None
        return self.db.get("SELECT * FROM authors WHERE id = %s", int(user_id))
#首页
class HomeHandler(BaseHandler):
    def get(self):


 #query 查询很多列
        entries = self.db.query("SELECT * FROM entries ORDER BY published "
                                "DESC LIMIT 5")
        if not entries:


     #redirect 重定向到一个url
            self.redirect("/compose")
            return


 #render 渲染一个模板,后面是参数
        self.render("home.html", entries=entries)

class EntryHandler(BaseHandler):
    def get(self, slug):


#get 得到一个值
        entry = self.db.get("SELECT * FROM entries WHERE slug = %s", slug)


#raise 触发一个错误信息,后面必须接类型
        if not entry: raise tornado.web.HTTPError(404)
        self.render("entry.html", entry=entry)

class ArchiveHandler(BaseHandler):
    def get(self):
        entries = self.db.query("SELECT * FROM entries ORDER BY published "
                                "DESC")
        self.render("archive.html", entries=entries)

class FeedHandler(BaseHandler):
    def get(self):
        entries = self.db.query("SELECT * FROM entries ORDER BY published "
                                "DESC LIMIT 10")
        self.set_header("Content-Type", "application/atom+xml")
        self.render("feed.xml", entries=entries)

class ComposeHandler(BaseHandler):
    #装饰器
    @tornado.web.authenticated
    def get(self):
        id = self.get_argument("id", None)
        entry = None
        if id:
            entry = self.db.get("SELECT * FROM entries WHERE id = %s", int(id))
        self.render("compose.html", entry=entry)
    @tornado.web.authenticated
    def post(self):
        id = self.get_argument("id", None)
        title = self.get_argument("title")
        text = self.get_argument("markdown")
        html = markdown.markdown(text)
        if id:
            entry = self.db.get("SELECT * FROM entries WHERE id = %s", int(id))
            if not entry: raise tornado.web.HTTPError(404)
            slug = entry.slug

        #execute是执行的意思
            self.db.execute(
                "UPDATE entries SET title = %s, markdown = %s, html = %s "
                "WHERE id = %s", title, text, html, int(id))
        else:
            slug = unicodedata.normalize("NFKD", title).encode(
                "ascii", "ignore")
            slug = re.sub(r"[^\w]+", " ", slug)
            slug = "-".join(slug.lower().strip().split())
            if not slug: slug = "entry"
            while True:
                e = self.db.get("SELECT * FROM entries WHERE slug = %s", slug)
                if not e: break
                slug += "-2"
            self.db.execute(
                "INSERT INTO entries (author_id,title,slug,markdown,html,"
                "published) VALUES (%s,%s,%s,%s,%s,UTC_TIMESTAMP())",
                self.current_user.id, title, slug, text, html)
        self.redirect("/entry/" + slug)

class AuthLoginHandler(BaseHandler, tornado.auth.GoogleMixin):
    @tornado.web.asynchronous
    def get(self):
        if self.get_argument("openid.mode", None):
            self.get_authenticated_user(self.async_callback(self._on_auth))
            return
        self.authenticate_redirect()

#这里定义一个函数,来供上面调用
    def _on_auth(self, user):
        if not user:
            raise tornado.web.HTTPError(500, "Google auth failed")
        author = self.db.get("SELECT * FROM authors WHERE email = %s",
                             user["email"])
        if not author:
            # Auto-create first author
            any_author = self.db.get("SELECT * FROM authors LIMIT 1")
            if not any_author:
                author_id = self.db.execute(
                    "INSERT INTO authors (email,name) VALUES (%s,%s)",
                    user["email"], user["name"])
            else:
                self.redirect("/")
                return
        else:
            author_id = author["id"]
        self.set_secure_cookie("blogdemo_user", str(author_id))
        self.redirect(self.get_argument("next", "/"))

class AuthLogoutHandler(BaseHandler):
    def get(self):
        self.clear_cookie("blogdemo_user")

    #get_argument为获得next参数的值,默认为"/"
        self.redirect(self.get_argument("next", "/"))

class EntryModule(tornado.web.UIModule):
    def render(self, entry):
        return self.render_string("modules/entry.html", entry=entry)
#入口函数
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()

最后总结一下:

1)tornado框架中提供的几个demo,都是以这种形式来创建一个应用的
2)对每一个控制器函数,要么是,只可能有2个对外的函数,一个是get,一个是post
3)数据库有3中调用方式,query,get,exec
4)获取参数的值使用 get_argument 函数
5)重定向用redirect 函数
6)所有的函数都是属性这个类的,所有都用self调用
7)渲染模板用render函数

Python 相关文章推荐
Python教程之全局变量用法
Jun 27 Python
python音频处理用到的操作的示例代码
Oct 27 Python
酷! 程序员用Python带你玩转冲顶大会
Jan 17 Python
python 信息同时输出到控制台与文件的实例讲解
May 11 Python
python使用pymongo操作mongo的完整步骤
Apr 13 Python
python 同时读取多个文件的例子
Jul 16 Python
python实现宿舍管理系统
Nov 22 Python
python异步Web框架sanic的实现
Apr 27 Python
利用PyQt5+Matplotlib 绘制静态/动态图的实现代码
Jul 13 Python
Opencv python 图片生成视频的方法示例
Nov 18 Python
Python虚拟环境virtualenv是如何使用的
Jun 20 Python
Python学习之os包使用教程详解
Mar 21 Python
python迭代器的使用方法实例
Nov 21 #Python
python生成器的使用方法
Nov 21 #Python
python单链表实现代码实例
Nov 21 #Python
python双向链表实现实例代码
Nov 21 #Python
python二叉树遍历的实现方法
Nov 21 #Python
python二叉树的实现实例
Nov 21 #Python
python冒泡排序算法的实现代码
Nov 21 #Python
You might like
咖啡界又出新概念,无需咖啡豆的分子咖啡
2021/03/03 咖啡文化
基于curl数据采集之单页面采集函数get_html的使用
2013/04/28 PHP
Codeigniter中禁止A Database Error Occurred错误提示的方法
2014/06/12 PHP
解决cPanel无法安装php5.2.17
2014/06/22 PHP
ThinkPHP模板Volist标签嵌套循环输出多维数组的方法
2016/03/23 PHP
Js之软键盘实现(js源码)
2007/01/30 Javascript
js 匿名调用实现代码
2009/06/19 Javascript
JavaScript 组件之旅(四):测试 JavaScript 组件
2009/10/28 Javascript
关于setInterval、setTimeout在jQuery中的使用注意事项
2011/09/28 Javascript
关于图片按比例自适应缩放的js代码
2011/10/30 Javascript
jQuery插件原来如此简单 jQuery插件的机制及实战
2012/02/07 Javascript
一个支持任意尺寸的图片上下左右滑动效果
2014/08/24 Javascript
jQuery多级手风琴菜单实例讲解
2015/10/22 Javascript
Javascript中字符串replace方法的第二个参数探究
2016/12/05 Javascript
详解Vue爬坑之vuex初识
2017/06/14 Javascript
jquery实现吸顶导航效果
2020/01/08 jQuery
详解Vue中的Props与Data细微差别
2020/03/02 Javascript
Element实现表格嵌套、多个表格共用一个表头的方法
2020/05/09 Javascript
vue 使用原生组件上传图片的实例
2020/09/08 Javascript
Python编程之微信推送模板消息功能示例
2017/08/21 Python
python数字图像处理之高级滤波代码详解
2017/11/23 Python
python中的字符串内部换行方法
2018/07/19 Python
Django 创建新App及其常用命令的实现方法
2019/08/04 Python
pytorch中如何使用DataLoader对数据集进行批处理的方法
2019/08/06 Python
PyCharm下载和安装详细步骤
2019/12/17 Python
Django:使用filter的pk进行多值查询操作
2020/07/15 Python
python em算法的实现
2020/10/03 Python
利用CSS3的transform做的动态时钟效果
2011/09/21 HTML / CSS
Sofft鞋官网:世界知名鞋类品牌
2017/03/28 全球购物
欧洲著名的珠宝和手表网上商城:uhrcenter
2017/04/10 全球购物
nohup的用法
2014/08/10 面试题
食品厂厂长岗位职责
2014/01/30 职场文书
学习自我鉴定
2014/02/01 职场文书
大学迎新生标语
2014/10/06 职场文书
2015年见习期工作总结
2014/12/12 职场文书
如何用H5实现好玩的2048小游戏
2022/07/23 HTML / CSS