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 图片验证码代码
Dec 07 Python
Python fileinput模块使用介绍
Nov 30 Python
Python和C/C++交互的几种方法总结
May 11 Python
Python实现复杂对象转JSON的方法示例
Jun 22 Python
python更改已存在excel文件的方法
May 03 Python
python pandas中对Series数据进行轴向连接的实例
Jun 08 Python
对pycharm代码整体左移和右移缩进快捷键的介绍
Jul 16 Python
pycharm 配置远程解释器的方法
Oct 28 Python
django框架用户权限中的session缓存到redis中的方法
Aug 06 Python
Python编写带选项的命令行程序方法
Aug 13 Python
python 如何区分return和yield
Sep 22 Python
python中类与对象之间的关系详解
Dec 16 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
ajax返回值中有回车换行、空格的解决方法分享
2013/10/24 PHP
php验证邮箱和ip地址最简单方法汇总
2015/10/30 PHP
PHP定时任务获取微信access_token的方法
2016/10/10 PHP
PHP函数按引用传递参数及函数可选参数用法示例
2018/06/04 PHP
动态样式类封装JS代码
2009/09/02 Javascript
写了10年的Javascript也未必全了解的连续赋值运算
2011/03/25 Javascript
JS解决url传值出现中文乱码的另类办法
2013/04/08 Javascript
addEventListener()第三个参数useCapture (Boolean)详细解析
2013/11/07 Javascript
JavaScript实现快速排序的方法
2015/07/31 Javascript
vue-resource + json-server模拟数据的方法
2017/11/02 Javascript
使用命令行工具npm新创建一个vue项目的方法
2017/12/27 Javascript
vue2.0安装style/css loader的方法
2018/03/14 Javascript
原生nodejs使用websocket代码分享
2018/04/07 NodeJs
vue-cli3+typescript初体验小结
2019/02/28 Javascript
Vue-cli3简单使用(图文步骤)
2019/04/30 Javascript
用vscode开发vue应用的方法步骤
2019/05/06 Javascript
跟老齐学Python之有点简约的元组
2014/09/24 Python
Python格式化输出%s和%d
2018/05/07 Python
python实现字符串中字符分类及个数统计
2018/09/28 Python
解决pyttsx3无法封装的问题
2018/12/24 Python
python使用pipeline批量读写redis的方法
2019/02/18 Python
python配置文件写入过程详解
2019/10/19 Python
用pushplus+python监控亚马逊到货动态推送微信
2021/01/29 Python
教你如何一步一步用Canvas写一个贪吃蛇
2018/10/22 HTML / CSS
HTML5 Canvas实现图片缩放、翻转、颜色渐变的代码示例
2016/02/28 HTML / CSS
韩国CJ食品专卖网:CJonmart
2016/09/11 全球购物
巴西图书和电子产品购物网站:Saraiva
2017/06/07 全球购物
戴尔新加坡官网:Dell Singapore
2020/12/13 全球购物
什么是数据抽象
2016/11/26 面试题
高职助产应届生自荐信
2013/09/24 职场文书
一封普通求职者的求职信
2013/11/20 职场文书
教师实习自我鉴定
2013/12/13 职场文书
班组拓展活动方案
2014/08/14 职场文书
二年级语文下册复习计划
2015/01/19 职场文书
倡议书作文
2015/01/19 职场文书
mysql字段为NULL索引是否会失效实例详解
2022/05/30 MySQL