Analysis and use of the tornado framework blog Module

Source: Internet
Author: User

Copy codeThe Code is as follows:
#! /Usr/bin/env python
#
# Copyright 2009 Facebook
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# Not use this file before t in compliance with the License. You may be obtain
# A copy of the License
#
# 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,
# Warranties or conditions of any kind, either express or implied. See
# 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 common configuration information, such as database connection information and 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 ")

# Define the Application information, which inherits tornado. web. Application
Class Application (tornado. web. Application ):
# _ Init _ automatic function call
Def _ init _ (self ):
# Here is the Controller corresponding to the url, and the following corresponds to a class to process the logic in it.
Handlers = [
(R "/", HomeHandler ),
(R "/archive", ArchiveHandler ),
(R "/feed", FeedHandler ),
(R "/entry/([^/] +)", EntryHandler ),
(R "/compose", ComposeHandler ),
(R "/auth/login", AuthLoginHandler ),
(R "/auth/logout", AuthLogoutHandler ),
]
# Settings, such as blog title, template directory, static file directory, xsrf, debugging or not
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,
)
# Then call the _ init _ function of tornado. web. Application class to load it in.
Tornado. web. Application. _ init _ (self, handlers, ** settings)

# Have one global connection to the blog DB guest SS all handlers
# Database connection information
Self. db = torndb. Connection (
Host = options. mysql_host, database = options. mysql_database,
User = options. mysql_user, password = options. mysql_password)

# Base class, inherited from tornado. web. RequestHandler, and the following classes all inherit from this class
Class BaseHandler (tornado. web. RequestHandler ):
# Attribute decorator: converts a db function into an attribute for later use.
@ Property
Def db (self ):
Return self. application. db
# Obtain the current user
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 ))

# Homepage
Class HomeHandler (BaseHandler ):
Def get (self ):
# Query multiple columns
Entries = self. db. query ("SELECT * FROM entries order by published"
"Desc limit 5 ")
If not entries:
# Redirect redirection to a url
Self. redirect ("/compose ")
Return
# Render renders a template, followed by Parameters
Self. render ("home.html", entries = entries)


Class EntryHandler (BaseHandler ):
Def get (self, slug ):
# Get A Value
Entry = self. db. get ("SELECT * FROM entries WHERE slug = % s", slug)
# Raise triggers an error message, which 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 10 ")
Self. set_header ("Content-Type", "application/atom + xml ")
Self. render ("feed. xml", entries = entries)


Class ComposeHandler (BaseHandler ):
# Decorator
@ 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 indicates execution.
Self.db.exe cute (
"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.exe cute (
"Insert into entries (author_id, title, slug, markdown, html ,"
"Published) VALUES (% 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 ()
# Define a function for the above call
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.exe cute (
"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 is the value of the next parameter. The default value 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)

# Entry functions
Def main ():
Tornado. options. parse_command_line ()
# Create a server
Http_server = tornado. httpserver. HTTPServer (Application ())
# Listening port
Http_server.listen (options. port)
# Start the service
Tornado. ioloop. IOLoop. instance (). start ()

# Call entry
If _ name _ = "_ main __":
Main ()

Summary:

1) Several demos provided in the tornado framework are used to create an application in this form.
2) For each controller function, either yes or only two external functions, one is get and the other is post.
3) There are three calling methods in the database: query, get, exec
4) use the get_argument function to obtain the parameter value.
5) redirect function for redirection
6) All functions belong to this class, And all functions are called by self.
7) use the render function for rendering templates

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.