#!/usr/bin/env python
#
# Copyright 2009 Facebook
#
# licensed under the Apache License, Version 2.0 (the "License"); May
# not use this file except in compliance with the License. For May obtain
# A copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# unless required by applicable or agreed to in writing, software
# Distributed under the License is distributed on ' as is ' basis, without
# warranties or CONDITIONS of any KIND, either express OR implied. 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
#定义一些通用的配置信息, such as database connection information, port information
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信息, it's inherited tornado.web.Application.
Class Application (Tornado.web.Application):
# __init__ function calls automatically
def __init__ (self):
#这里就是url对应的控制器, each of these corresponds to a class that handles the logic inside.
handlers = [
(r "/", Homehandler),
(r "/archive", Archivehandler),
(r "/feed", Feedhandler),
(r "/entry/([^/]+)", Entryhandler),
(r "/compose", Composehandler),
(r "/auth/login", Authloginhandler),
(r "/auth/logout", Authlogouthandler),
]
#设置, such as blog title, template directory, static file directory, XSRF, whether debugging
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,
)
The __init__ function of the Web.application class is loaded in #然后调用tornado.
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)
#基类, inherited from Tornado.web.RequestHandler, and subsequent classes are
Class Basehandler (Tornado.web.RequestHandler) that inherit this class:
#属性装饰器, Make the DB function a property that makes it easy to use
@property
def db (self) directly in the following:
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 Query many columns
entries = self.db.query ("SELECT * from Entries ORDER by published"
"DESC LIMIT 5")
If not entries:
#redirect Redirect to a URL
self.redirect ("/compose")
return
#render render a template, followed by parameters
Self.render ("home.html", entries=entries)
Class Entryhandler (Basehandler):
def get (self, slug):
#get Get a value
Entry = Self.db.get ("SELECT * from entries WHERE slug =%s", slug)
#raise triggers an error message that must be followed by a type
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")
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 ()
#这里定义一个函数, for the above call
def _on_auth (self, user):
If not User:
Raise Tornado.web.HTTPError ("Google auth failed")
Author = self.db.get ("select * FROM authors WHERE email =%s")
user["Email"])
If not author:
# Auto-create-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参数的值, the default is "/"
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 The Tornado framework provides several demos that are used in this form to create an application
2 for each controller function, or, there may be only 2 external functions, one is get, one is post
3 The database is called in 3 ways, query,get,exec
4 Get the value of the parameter using the Get_argument function
5) redirect with redirect function
6 All functions are attributes of this class, all are called with self
7) Rendering template with render function