tornado框架blog模块分析与使用

392次阅读  |  发布于5年以前

复制代码 代码如下:

!/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()

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8