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 socket编程实例详解
May 27 Python
Python中使用ElementTree解析XML示例
Jun 02 Python
Python基于分水岭算法解决走迷宫游戏示例
Sep 26 Python
用python统计代码行的示例(包括空行和注释)
Jul 24 Python
python的依赖管理的实现
May 14 Python
PyTorch搭建一维线性回归模型(二)
May 22 Python
树莓派使用USB摄像头和motion实现监控
Jun 22 Python
python实现简单银行管理系统
Oct 25 Python
Python 从attribute到property详解
Mar 05 Python
keras的三种模型实现与区别说明
Jul 03 Python
Python实现http接口自动化测试的示例代码
Oct 09 Python
Python命令行参数argv和argparse该如何使用
Feb 08 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
萌王史莱姆”萌王性别尴尬!那“萌战”归女组还是男?
2018/12/17 日漫
PHP中set_include_path()函数相关用法分析
2016/07/18 PHP
Yii2使用$this->context获取当前的Module、Controller(控制器)、Action等
2017/03/29 PHP
PHP实现对文件锁进行加锁、解锁操作的方法
2017/07/04 PHP
Laravel框架Eloquent ORM修改数据操作示例
2019/12/03 PHP
关于viewport,Ext.panel和Ext.form.panel的关系
2009/05/07 Javascript
巧用js提交表单轻松解决一个页面有多个提交按钮
2013/11/17 Javascript
Javascript进制转换实例分析
2015/05/14 Javascript
jQuery Validation Plugin验证插件手动验证
2016/01/26 Javascript
文本框只能输入数字的js代码(含小数点)
2016/07/10 Javascript
JS获取一个未知DIV高度的方法
2016/08/09 Javascript
jquery基本选择器匹配多个元素的实现方法
2016/09/05 Javascript
IntelliJ IDEA编辑器配置vue高亮显示
2019/09/26 Javascript
编写一个javascript元循环求值器的方法
2020/04/14 Javascript
JavaScript cookie原理及使用实例
2020/05/08 Javascript
vue中用 async/await 来处理异步操作
2020/07/18 Javascript
JS时间戳与日期格式互相转换的简单方法示例
2021/01/30 Javascript
使用Python进行稳定可靠的文件操作详解
2013/12/31 Python
Python中SOAP项目的介绍及其在web开发中的应用
2015/04/14 Python
简单的python后台管理程序
2017/04/13 Python
浅谈Python2.6和Python3.0中八进制数字表示的区别
2017/04/28 Python
Python pycharm 同时加载多个项目的方法
2019/01/17 Python
python爬虫解决验证码的思路及示例
2019/08/01 Python
python实现的生成word文档功能示例
2019/08/23 Python
pytorch实现用CNN和LSTM对文本进行分类方式
2020/01/08 Python
Python如何执行精确的浮点数运算
2020/07/31 Python
Python操作PostgreSql数据库的方法(基本的增删改查)
2020/12/29 Python
CSS3制作翻转效果_动力节点Java学院整理
2017/07/11 HTML / CSS
html5.2 dialog简介详解
2018/02/27 HTML / CSS
西班牙拥有最佳品牌的动物商店:Animalear.com
2018/01/05 全球购物
英国建筑用品在线:Building Supplies Online(BSO)
2018/04/30 全球购物
经典C++面试题一
2016/11/06 面试题
教师求职信范文分享
2013/12/27 职场文书
求职简历自我评价范例
2014/03/12 职场文书
python实现图片批量压缩
2021/04/24 Python
Python+OpenCV实现在图像上绘制矩形
2022/03/21 Python