文章详情页 您现在的位置是:网站首页>文章详情

关于tornado框架

图片丢失 Jeeyshe 发表于:2019年6月21日 23:20 分类:【日常笔记 340次阅读

之前的笔记

这里是以前自己学tornado框架做的笔记,我放在有道云上,周末我又看了一下。 tornado的学习笔记

以下关键点笔记记录于2019-06-26日

Django是python语言中最为全面、典型的web框架,我对django较熟悉,之后我自己又看了flask, bottle, 现在又看了tornado, 我不得不说,django确实是最值得学习的!

tornado快速上手关键点

(一)例子: app加载路由、配置,传给httpserver、开启ellpo事件循环

-----handlers.py

from tornado.web import RequestHandler

import db
import ex
from index import utils
from db import get_session, open_session


class BaseHandler(RequestHandler):
    """
    一些公共的操作
    """
    session = None

    def prepare(self):
        setattr(self, 'session', db.open_session())

    def on_finish(self):
        if self.session:
            self.session.close()


class IndexHandler(BaseHandler):

    def get(self, *args, **kwargs):
        area = db.Area(name=self.get_argument('name', utils.random_string()))
        self.session.add(area)
        self.session.commit()
        self.render('index.html', **{'web': area})


class AccountAreaHandler(BaseHandler):

    def get(self, *args, **kwargs):
        accounts = self.session.query(db.Account).all()
        self.write(json.dumps([{'area': a.area.name, 'name': a.username} for a in accounts]))


class ReverUrlTestHandler(RequestHandler):

    def get(self, *args, **kwargs):
        self.render('test_url_reverse.html')

------ urls.py

from tornado.web import URLSpec as U
# fixme: from tornado.web import url 这个url就是URLSpec


# 实际上我怎么觉得这个URLSpec就是来搞笑的,直接传元祖也没什么问题

from index import handlers

url_list = (
    U(r'/index.html', handlers.IndexHandler),
    U(r'/account', handlers.AccountAreaHandler, {}, '222'),
    ('/xxx', handlers.ReverUrlTestHandler, {}, 'xxx'),
)

-----run.py

from tornado import web
from tornado.ioloop import IOLoop

from index.urls import url_list
from config import SETTINGS

if __name__ == '__main__':
    app = web.Application(handlers=url_list, debug=True, autoreload=True, **SETTINGS)
    app.listen(8000)
    IOLoop.current().start()

(二)tornado响应: 继承tornado.web.RequestHandler类,实现get...delete请求方式对应的function即可

RequestHandler直接父类:object,他是tornado提供的一种基础handler

实现的方法及作用:
    initialize: 在__init__方法最后进行调用,是__init__方法的扩展,用于初始化handler实例时扩展操作,父类pass
    headgetpostoptionsputpatchdelete七种对应请求方式的方法,目前只是抽象出来,父类raise 405,意味着继承这个类的必须自己实现对应方法覆盖他
    prepareon_finish,这两个方法分别在执行请求视图(get、header、options等)之前之后调用,父类pass
    set_default_headers,设置默认响应头,父类pass
    get_argumentsget_query_arguments,获取请求参数
    cookiesget_cookieset_cookieclear_cookieclear_all_cookiesset_secure_cookieget_secure_cookie,和cookie相关的操作
    rediect,重定向,通过参数决定是永久还是临时
    write,用于返回响应,相应数据可以是bytes, unicode_type, dict三种类型
    renderrender_stringget_template_namespacecreate_template_loader,和模板渲染有关的函数
    finish,结束响应,清空buff,调用do_finish等
    get_current_user,父类pass,自己覆盖用以进行authenticate,覆盖后可self.current_user取用
    _execute,此方法是响应请求的关键方法,他从handler实例中寻找对应于请求的handler,以及default_handler,没有则raise405,否则执行对应函数(此方法使用gen.croutine装饰,异步执行)

if self.request.method not in self.SUPPORTED_METHODS:
    raise HTTPError(405)
...
method = getattr(self, self.request.method.lower())
result = method(*self.path_args, **self.path_kwargs)


class BaseHandler(RequestHandler):
    """
    一些公共的操作
    """
    session = None

    def prepare(self):
        setattr(self, 'session', db.open_session())

    def on_finish(self):
        if self.session:
            self.session.close()

(三)tornado路由:给app传入一个[(regex, handler_cls, kw_dict, name)]这样的路由列表即可

(1) 创建app实例时传入

url_list = (
    U(r'/index.html', handlers.IndexHandler),
    U(r'/account', handlers.AccountAreaHandler, {}, '222'),
    ('/xxx', handlers.ReverUrlTestHandler, {}, 'xxx'),
)
if __name__ == '__main__':
    app = web.Application(handlers=url_list, debug=True, autoreload=True, **SETTINGS)
    app.listen(8000)
    IOLoop.current().start()

(2)创建app实例之后添加(也可用于子域名)

url_list = (
    U(r'/index.html', handlers.IndexHandler),
    U(r'/account', handlers.AccountAreaHandler, {}, '222'),
    ('/xxx', handlers.ReverUrlTestHandler, {}, 'xxx'),
)
url_list2 = [
    .....如上
]
if __name__ == '__main__':
    app = web.Application(handlers=url_list, debug=True, autoreload=True, **SETTINGS)
    app.add_handlers('.*$', url_list2)
    app.listen(8000)
    IOLoop.current().start()

(四)tornado操作数据库:他自己的torndb功能太简单了,我们使用sqlalchemy来进行orm操作

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from multiprocessing import cpu_count
from contextlib import contextmanager

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, DateTime, Boolean, func, Index, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.schema import MetaData

mysql = {
    'username': 'root',
    'password': 'ljX.07',
    'host': '127.0.0.1',
    'port': 3306,
    'database_name': 'idea'
}

engine_str = 'mysql+mysqldb://{username}:{password}@{host}:{port}/{database_name}?charset=utf8'.format(**mysql)
engine = create_engine(
    engine_str,
    encoding='utf8',
    echo=False,
    pool_size=cpu_count() * 2,
    max_overflow=cpu_count(),
    pool_recycle=600,
    pool_timeout=600,
)
meta_data = MetaData(bind=engine)


@contextmanager
def get_session():
    Session = sessionmaker(bind=engine, autocommit=False, autoflush=False, expire_on_commit=False)
    session = Session()
    yield session
    session.close()


def open_session():
    Session = sessionmaker(bind=engine, autocommit=False, autoflush=False, expire_on_commit=False)
    session = Session()
    return session


class Base(object):
    __table_args__ = {
        "mysql_engine": "InnoDB",
        "mysql_charset": "utf8"
    }


BaseModel = declarative_base(bind=engine, name='BaseModel', metadata=meta_data, cls=Base)


class Area(BaseModel):
    """
    区域表
    """
    __tablename__ = 'area'

    # 自增id
    id = Column(name='id', type_=Integer, autoincrement=True, primary_key=True, comment='id')
    # 字符串类型
    name = Column(name='name', type_=String(20), nullable=False, unique=True, comment=u'名字')
    # 时间自动更新
    add = Column(name='add', type_=DateTime, server_default=func.now(), comment=u'添加时间')
    mod = Column(name='mod', type_=DateTime, server_onupdate=func.now(), comment=u'最近更新')
    # 布尔类型
    is_active = Column(name='is_active', type_=Boolean, default=True, comment=u'是否可用')

    def __repr__(self):
        return self.name


class Account(BaseModel):
    """
    账户表
    """
    __tablename__ = 'account'

    id = Column(name='id', type_=String(32), primary_key=True, comment='uuid')
    username = Column(name='username', type_=String(20), unique=True, comment=u'用户名')
    area_id = Column('area_id', ForeignKey(column='area.id', ondelete='CASCADE'))
    area = relationship('Area', backref='Account_area_id')
    add = Column(name='add', type_=DateTime, server_default=func.now(), comment=u'创建时间')
    mod = Column(name='mod', type_=DateTime, server_onupdate=func.now(), comment=u'上次变更')
    is_active = Column(name='is_active', type_=Boolean, default=True, comment=u'是否可用')

    def __repr__(self):
        return self.username

if __name__ == '__main__':
    BaseModel.metadata.create_all(checkfirst=True)


这里的操作有几个关键点
  • 创建engine,创建session

  • declarative_base创建一个基类,之后我们所有的表都继承这个基类,之后基类就可以一键生成表,描述表的关系

  • 使用orm时,我们创建一个session, 然后session.add, session.query等等操作带入model类即可

class IndexHandler(BaseHandler):

    def get(self, *args, **kwargs):
        area = db.Area(name=self.get_argument('name', utils.random_string()))
        self.session.add(area)
        self.session.commit()
        self.render('index.html', **{'web': area})

(五)tornado后端渲染

tornado如众多web框架一样支持模板语言后端渲染,他的RequestHandler提供了render和render_string两个function来执行这一操作,模板语法类似于jinja2, django的DTL等

  • handler这么写

class TemplateHandler(RequestHandler):
    """
    模板渲染示例
    """
    def get(self, *args, **kwargs):
        ctx = {
            'email': 'jeeyshe@gmail.com',
            'site': 'https://www.lujianxin.com',
            'lines': ['江山不换韩云汐', '青城山下白素贞', '《落花成泥》', '《叹云兮》']
        }
        self.render('info.html', **ctx)


  • html模板语言这么写

<span>联系方式:</span>: {{ email }}<br>
<span>网站地址:</span>: <a href="{{ site }}" target="_blank">{{ site }}</a><br>
{% for line in lines %}
<p>{{ line }}</p>
{%  end for %}


  • 渲染后的效果

after_render.png

最后说一句:web框架大同小异,django确实是python语言中最全面、典型的web框架


版权声明 本文属于本站  原创作品,文章版权归本站及作者所有,请尊重作者的创作成果,转载、引用自觉附上本文永久地址: https://www.lujianxin.com/x/art/7ji2jdhiscqr

文章评论区

作者名片

图片丢失
  • 作者昵称:Jeeyshe
  • 原创文章:18篇
  • 转载文章:3篇
  • 加入本站:217天

站点信息

  • 运行天数:218天
  • 累计访问:25177人次
  • 今日访问:136人次
  • 原创文章:24篇
  • 转载文章:4篇
  • 微信公众号:第一时间获取更新信息