Tornado入门

慕课网:https://coding.imooc.com/class/290.html

 

工具列表

Peewee

简介:Peewee is a simple and small ORM. It has few (but expressive) concepts, making it easy to learn and intuitive to use.

官网:http://docs.peewee-orm.com/en/latest/index.html

peewee-async

peewee-async is a library providing asynchronous interface powered by asyncio for peewee ORM.

官网:https://peewee-async.readthedocs.io/en/latest/

WTForms

提供表单验证

官网地址:https://wtforms.readthedocs.io/en/stable/

aiofiles

github: https://github.com/Tinche/aiofiles

 

 

表单的增删改查

 

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户注册案例</title>
</head>
<body>
<form action="/register" method="post" enctype="multipart/form-data">
    {% module xsrf_form_html() %}
    <!--隐藏表单项,应用场景:某些数据对用户而言是没有意义的,用户不需要看到这些数据,但是服务器又需要,那么这-->
    <!--时候就可以使用隐藏表单项-->
    <input type="hidden" name="flag" value="true"/>
    <table width="400px" height="400px">
        <tr>
            <!--colspan:单元格跨几列-->
            <td colspan="2">
                <h4>用户注册</h4>
                <hr/>
            </td>
        </tr>

        <tr>
            <td>用户名:</td>
            <td>
                <!--用户名:普通文本输入框-->
                <input type="text" name="username" value="请输入用户名..."/>
            </td>
        </tr>

        <tr>
            <td>密码:</td>
            <td>
                <!--密码:密码框-->
                <input type="password" name="password"/>
            </td>
        </tr>

        <tr>
            <td>性别:</td>
            <td>
                <!--性别:单选框,单选框input标签,type=radio 同一组的单选框只能选择其中一个
                  单选框如果需要分组,那么必须保持name的属性值一致。如果需要默认选中某一个,那么需要添加
                  checked属性-->
                男:<input type="radio" name="sex" value="man" checked/>
                女:<input type="radio" name="sex" value="woman"/>
            </td>
        </tr>

        <tr>
            <td>爱好:</td>
            <td>
                <!--兴趣爱好:复选框-->
                游泳:<input type="checkbox" name="hobbit" value="swimm"/>
                上网:<input type="checkbox" name="hobbit" value="surf"/>
                电影:<input type="checkbox" name="hobbit" value="movie"/>
                看书:<input type="checkbox" name="hobbit" value="read"/>
            </td>
        </tr>

        <tr>
            <td>学历:</td>
            <td>
                <!--学历:下拉框,下拉框使用的是select标签-->
                <select name="education">
                    <option value="bs">博士</option>
                    <option value="ss">硕士</option>
                    <option value="bk">本科</option>
                    <option value="dz">大专</option>
                </select>
            </td>
        </tr>

        <tr>
            <td>照片:</td>
            <td>
                <!--照片:文件表单项-->
                <input type="file" name="image"/>
            </td>
        </tr>

        <tr>
            <td>个人简介:</td>
            <td>
                <!--个人简介:文本域 标签:textarea-->
                <textarea cols="40" rows="10" name="introduction"></textarea>
            </td>
        </tr>

        <tr align="center">
            <!--colspan:单元格跨几列-->
            <td colspan="2">
                <!--普通按钮-->
                <input type="button" value="普通按钮"/>
                <!--重置表单项-->
                <input type="reset" value="重置"/>
                <!--提交按钮:提交表单的数据到服务器上-->
                <input type="submit" value="注册"/>
            </td>
        </tr>

    </table>
</form>

</body>
</html>
View Code

handler.py

class RegisterHandler(BaseHandler):
    def get(self):
        return self.render("register.html")

    def post(self):
        username = self.get_argument('username')
        password = self.get_argument('password')
        sex = self.get_argument('sex')
        hobbits = self.get_arguments('hobbit')
        education = self.get_argument('education')
        introduction = self.get_argument('introduction')
        img_files = self.request.files.get('image')
        if img_files:
            img_file = img_files[0]
            handle_uploaded_file(img_file)
        context = {
            'username': username,
            'password': password,
            'sex': sex,
            'hobbits': hobbits,
            'education': education,
            'introduction': introduction,
        }
        return self.render("register.html", **context)
View Code

 正式项目案例

项目结构

 

server.py 管理服务器

# coding:utf-8

import tornado.locks
import tornado.web
import tornado.ioloop
import tornado.options
import tornado.httpserver
from tornado.options import options, define

import config
import aiomysql

from urls import urls

define("port", default=8000, type=int, help="run server on the given port")


class Application(tornado.web.Application):
    def __init__(self, db):
        handlers = urls
        settings = config.settings
        self.db = db
        super(Application, self).__init__(handlers, **settings)


async def main():
    options.log_file_prefix = config.log_path
    options.logging = config.log_level
    tornado.options.parse_command_line()
    pool = await aiomysql.create_pool(
        **config.mysql_base_options,
    )
    async with pool.acquire() as db:
        app = Application(db)
        app.listen(options.port)

        # In this demo the server will simply run until interrupted
        # with Ctrl-C, but if you want to shut down more gracefully,
        # call shutdown_event.set().
        shutdown_event = tornado.locks.Event()
        await shutdown_event.wait()
    pool.close()
    await pool.wait_closed()


if __name__ == "__main__":
    tornado.ioloop.IOLoop.current().run_sync(main)

config.py管理项目配置

# coding:utf-8

import os

BASE_ROOT = os.path.dirname(__file__)
MEDIA_ROOT = os.path.join(BASE_ROOT, 'media')

# Application配置参数
settings = dict(
    template_path=os.path.join(BASE_ROOT, "templates"),
    static_path=os.path.join(BASE_ROOT, "static"),
    cookie_secret="FhLXI+BRRomtuaG47hoXEg3JCdi0BUi8vrpWmoxaoyI=",
    xsrf_cookies=True,
    login_url='/login',
    debug=True
)

# 数据库配置参数
mysql_options = dict(
    host="127.0.0.1",
    port=3306,
    user="root",
    password="123456",
    db="my_db",
)


# Redis配置参数
# redis_options = dict(
#     host="127.0.0.1",
#     port=6379
# )

# 日志配置
log_path = os.path.join(os.path.dirname(__file__), "logs/log")
log_level = "debug"

# 密码加密密钥
passwd_hash_key = "nlgCjaTXQX2jpupQFQLoQo5N4OkEmkeHsHD9+BBx2WQ="

 BaseHandler主要用来被继承

# coding:utf-8
import tornado
import tornado.util
from tornado.web import RequestHandler


class NoResultError(Exception):
    pass


class BaseHandler(tornado.web.RequestHandler):
    def row_to_obj(self, row, cur):
        """Convert a SQL row to an object supporting dict and attribute access."""
        obj = tornado.util.ObjectDict()
        for val, desc in zip(row, cur.description):
            obj[desc[0]] = val
        return obj

    async def execute(self, stmt, *args):
        """Execute a SQL statement.

            Must be called with ``await self.execute(...)``
        """
        async with self.application.db.cursor() as cur:
            await cur.execute(stmt, args)

    async def query(self, query, *args):
        """Query for a list of results.
        
            Typical usage::
                results = await self.query(...)
            Or::
                for row in await self.query(...)
        """
        async with self.application.db.cursor() as cur:
            await cur.execute(query, args)
            return [self.row_to_obj(row, cur) for row in await cur.fetchall()]

    async def query_one(self, query, *args):
        """Query for exactly one result.

            Raises NoResultError if there are no results, or ValueError if
            there are more than one.
        """
        results = await self.query(query, *args)
        if len(results) == 0:
            raise NoResultError()
        elif len(results) > 1:
            raise ValueError("Expected 1 result, got %d" % len(results))
        return results[0]

    async def prepare(self):
        # get_current_user cannot be a coroutine, so set
        # self.current_user in prepare instead.
        user_id = self.get_secure_cookie("user_id")
        if user_id:
            self.current_user = await self.query_one(
                "SELECT * FROM zd_user WHERE id = %s", user_id
            )

    # async def any_author_exists(self):
    #     return bool(await self.query("SELECT * FROM authors LIMIT 1"))

IndexHandler主要用来处理业务逻辑,如:用户登录逻辑

import tornado.web
from handlers.BaseHandler import BaseHandler


class Index(BaseHandler):
    @tornado.web.authenticated
    async def get(self):
        self.render("index.html")  # 渲染主页模板,并返回给客户端。


# def handle_uploaded_file(img_file):
#     destination = os.path.join(config.MEDIA_ROOT, img_file['filename'])
#     if os.path.exists(destination):
#         return
#     with open(destination, 'wb+') as file:
#         file.write(img_file['body'])


class LoginHandler(BaseHandler):
    def get(self):
        self.render('login.html')

    async def post(self):
        username = self.get_argument('username')
        password = self.get_argument('password')

        query = "SELECT * FROM zd_user where login_name=%s"
        user = await self.query_one(query, username)
        if user:
            self.set_secure_cookie("user_id", user.id)
            self.redirect('/index')
        else:
            self.write({'msg': 'fail_user'})

 JS加载JSON数据

JSON.parse('{% raw resources %}')

URL路由传参 

# urls.py
from tornado.web import url
from apps.pile.views import *

urlpatterns = [
    url("/pile/open", PileHandler, {'command': "open"}),
    url("/pile/close", PileHandler, {'command': "close"}),
]
# views.py
class PileHandler(BaseHandler):
    # 获取动态设置的参数command
    async def initialize(self, command):  # 动态参数要与url路由中设置的参数必须一样
        self.command = command

    async def get(self, *args, **kwargs):
        name = self.get_query_argument("name")
        await self.finish(json.dumps({"command": self.command}, default=json_serial))

    async def post(self, *args, **kwargs):
        name = self.get_body_argument("name")
        await self.finish(json.dumps({"a": name}, default=json_serial))

 

posted @ 2019-02-11 16:43  逐梦客!  阅读(522)  评论(0)    收藏  举报