Tornado Web 开发 框架搭建 (1)

环境配置

使用 python 3.3 和tornado, 其实也是个人兴趣问题,然后数据库也使用mysql, 这里 使用oracle 自家的 mysql-connector. 自然,orm就选择 sqlalchemy了. 模板引擎使用jinja2, form验证考虑wtforms。

    

    项目配置大概如上。之后可能使用全文检索和数据库逐步更新功能,因此又附加了 alembic 和 whoosh 俩个包。

入口

先看下 入口 server.py


#coding=utf-8

import tornado.ioloop
from tornado.options import define, options
from lib.base import MainApplication
from lib.routes import make_handlers, include
from settings import URL_PREFIX
# Options
#define("port", default=8888, help="run on the given port", type=int)
#define("db_path", default='sqlite:tmp/test.db', type=str)

settings = {
    "template_path": "template",
    "static_path": "static",
    "debug": True,
    #"logging": "debug",
    "login_url": '/login',
    "cookie_secret": "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=",
    "xsrf_cookies": True,
}

#application = MainApplication([#tornado.web.Application([
#    (r"/", MainHandler),
#],**settings)
application = MainApplication(make_handlers(URL_PREFIX,
                                            (r'/', include('handlers.index')),
                                            (r'/', include('handlers.user')),
                                            (r'/', include('handlers.userGroup')),
), **settings)

if __name__ == "__main__":
    application.listen(8888)
    tornado.options.options.logging = "debug"
    tornado.options.parse_command_line()
    tornado.ioloop.IOLoop.instance().start()

ROUTE

为了给tornado 实现 每个handler 单独配置url, 

类似这样  

@route('login/', name='login')
class LoginHandler(BaseHandler):
    @tornado.web.asynchronous
    def get(self):
        self.render("login.html")
这里自己建了一个routes.py 参考 https://github.com/troolee/tornado-routes


#coding=utf-8
from pprint import pformat
import re
import logging

from tornado import web
from tornado.web import URLSpec


logger = logging.getLogger(__name__)

__ALL__ = ('make_handlers', 'include', 'route', 'routes', )


def handler_repr(cls):
    return re.search("'(.+)'", repr(cls)).groups()[0]


class HandlersList(object):
    def __init__(self, prefix, items):
        self.prefix = prefix
        self.items = items

    def get_handler_name(self, handler, r):
        name = getattr(handler, 'url_name', None)
        if name:
            return name
        if hasattr(handler, 'get_url_name'):
            name = handler.get_url_name(*r)
        if name:
            return name
        if len(r) == 3 and 'url_name' in r[2]:
            name = r[2].pop('url_name')
        if name:
            return name
        return handler_repr(handler)

    def build(self, prefix=None):
        prefix = prefix or self.prefix or ''

        res = []
        for r in self.items:
            print(r)
            route = '/' + '/'.join([prefix.strip('/')] + r[0].strip('/').split('/')).strip('/')
            print(route)
            if isinstance(r[1], HandlersList):
                res += r[1].build(route)
            elif isinstance(r[1], str):
                m = r[1].split('.')
                ms, m, h = '.'.join(m[:-1]), m[-2], m[-1]
                m = __import__(ms, fromlist=[m], level=0)
                handler = getattr(m, h)[0]
                d = {'name': self.get_handler_name(handler, r)}
                #d.update(r[2:])
                d['kwargs'] = {}
                if len(r) == 3:
                    d['kwargs'] = r[2]
                res.append(URLSpec(route, handler, **d))
                if len(route) > 1:
                    #d['kwargs']['url'] = route;
                    d.pop('name')
                    res.append(URLSpec(route + '/', handler, **d))
            else:
                handler = r[1:][0]
                d = {'name': self.get_handler_name(handler, r)}
                d['kwargs'] = {}
                if len(r) == 3:
                    d['kwargs'] = r[2]
                res.append(URLSpec(route, handler, **d))
                if len(route) > 1:
                    #d['kwargs']['url'] = route;
                    d.pop('name')
                    res.append(URLSpec(route + '/', handler, **d))

        return res


def make_handlers(prefix, *args):
    res = tuple(HandlersList(prefix, args).build())
    rr = [(x.regex.pattern, x.handler_class, x.kwargs, x.name) for x in res]
    logger.debug('\n' + pformat(sorted(rr, key=lambda a: a[0]), width=200))

    return res


def include(module):
    def load_module(m):
        m = m.split('.')
        ms, m = '.'.join(m), m[-1]
        m = __import__(ms, fromlist=[m], level=0)
        return m

    if isinstance(module, (str,)):
        module = load_module(module)

    routes = []
    for member in dir(module):
        member = getattr(module, member)
        if isinstance(member, type) and issubclass(member, web.RequestHandler) and hasattr(member, 'routes'):
            i = 1
            for route_path, route_params in member.routes:
                route_path.strip('/')
                if not route_params:
                    route_params = {}
                if 'url_name' not in route_params:
                    route_params['url_name'] = '%s~%d' % (handler_repr(member), i)
                routes.append((route_path, member, route_params))
                i += 1
        elif isinstance(member, type) and issubclass(member, web.RequestHandler) and hasattr(member, 'route_path'):
            route_path, route_params = member.route_path, member.route_params

            route_path.strip('/')
            if route_params:
                routes.append((route_path, member, route_params))
            else:
                routes.append((route_path, member))
        elif isinstance(member, type) and issubclass(member, web.RequestHandler) and hasattr(member, 'rest_route_path'):
            route_path, route_params = member.rest_route_path, member.route_params

            route_path.strip('/')
            if route_params:
                routes.append((route_path, member, route_params))
                routes.append((route_path + r'/([0-9]+)', member, route_params))
            else:
                routes.append((route_path, member))
                routes.append((route_path + r'/([0-9]+)', member))
    return HandlersList(None, routes)


route_classes = {}


def route(path, params=None, name=None):
    params = params or {}

    def decorator(cls):
        if repr(cls) in route_classes:
            raise Exception('Cannot bind route "%s" to %s. It already has route to "%s".' %
                            (path, cls, route_classes[repr(cls)]))
        route_classes[repr(cls)] = path
        cls.route_path = path
        cls.route_params = params
        url_name = params.pop('url_name', name)
        cls.url_name = url_name
        return cls

    return decorator


def routes(*routes):
    def decorator(cls):
        cls.routes = routes
        return cls

    return decorator

同时支持url后缀带斜杠和不带斜杠的处理

配置好的route 还可以这样用

<a href="{{ reverse_url('login') }}">Login</a>

转载于:https://my.oschina.net/stardriver/blog/163035

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值