• Tornado-基于正则的路由和动态分页


    概览

    这一小节涉及了三部分内容:

    1.动态分页设计

    2.基本的路由系统以及基于正则的路由

    3.模块引擎的继承和导入

    4.web项目文件夹和ReuquestHandler的分类

    5.跨站脚本攻击

    文件结构

     

    Python代码

    start.py

    from tornado.ioloop import IOLoop
    import tornado.web
    from controllers import account
    from controllers import home
    from controllers import extend
    
    
    settings = {
            "template_path": "views",  # 配置html文件路径
            "static_path": "statics",  # 配置静态文件路径
        }
    
    
    # 路由映射
    # 基于正则路由是为了解决基本路由僵化的一一对应问题,可以实现一个类处理多种url
    application = tornado.web.Application([
        #
        (r"/index/?(?P<page>d*)", home.IndexHandler),
        (r"/login", account.LoginHandler),
        # 模板继承与导入
        (r"/extend/index", extend.ExtendIndexHandler),
        (r"/extend/home", extend.ExtendHomeHandler),
    ], **settings)
    
    
    # 启动服务端
    if __name__ == "__main__":
        application.listen(8888)
        IOLoop.instance().start()
    View Code

    controllers -account.py -extend.py -home.py

    import tornado.web
    
    
    class LoginHandler(tornado.web.RequestHandler):
        def get(self):
            pass
    
    
    class LogoutHandler(tornado.web.RequestHandler):
        def get(self):
            pass
    
    
    class RegisterHandler(tornado.web.RequestHandler):
        def get(self):
            pass
    account.py
    import tornado.web
    
    
    class ExtendIndexHandler(tornado.web.RequestHandler):
        def get(self):
            self.render('extend/index.html')
    
    
    class ExtendHomeHandler(tornado.web.RequestHandler):
        def get(self):
            self.render('extend/home.html')
    extend.py
    import tornado.web
    from commons.pagination import Pagination
    
    INFO_LIST = [
        {'name': 'yeff', 'age': '23'},
    ]
    for i in range(99):
        INFO_LIST.append({
            'name': 'a'+str(i), 'age': '0'+str(i)
        })
    
    
    class IndexHandler(tornado.web.RequestHandler):
        def get(self, page):
            pn = Pagination(page, 5, INFO_LIST)
            str_pages = pn.get('/index')
            display_list = pn.items[pn.start_item:pn.end_item]
            self.render("home/index.html", info_list=display_list, current_page=page, page_nums=str_pages)
    
        def post(self, page):
            # 之前提交时,action连接的是/index,因此在没有添加current_page参数之前,page都只会为空字符串
            name = self.get_argument('name')
            age = self.get_argument('age')
            _dic = {'name': name, 'age': age}
            INFO_LIST.append(_dic)
            self.redirect("/index/" + page)
    home.py

    commons -Pagination.py

    class Pagination(object):
        def __init__(self, current_page, items_per_page, items):
            try:
                current_page = int(current_page)
                assert current_page > 0
                assert current_page < len(items)
            except:
                current_page = 1
            self.current_page = current_page
            self.items = items
            self.per_page = items_per_page
    
        @property
        def start_item(self):
            # 设若有n个元素,每页显示a个,则第x页的元素列表就是
            # 前一页的最后一个元素是第(x-1)*a个元素,下一个就是第[(x-1)*a]+1个元素,序号就是(x-1)*a
            return (self.current_page - 1) * self.per_page
    
        @property
        def end_item(self):
            # 当前页的最后一个元素是第ax个,序号就是ax-1,但因为切片操作留头切尾,因此还要再+1,结果就是ax
            return self.current_page * self.per_page
    
        # Create page numbers
        def get(self, base_url=''):
            actual_pages, _remainder = divmod(len(self.items), self.per_page)
            actual_pages += 1 if _remainder > 0 else 0
    
            start = self.current_page - 5
            end = self.current_page + 5
    
            # 防止页码变成负数,以及大于实际页数
            # 这里的条件限制类似放大镜那一节防止超出边界时的设置
            # 这里用到了多重赋值和三元运算符
            # 多重赋值本质就是tuple packing(元组打包)和 Sequence unpacking(序列解包)
            # A = Y if X else Z
            # 只有当X为真时才会执行表达式Y,而只有当X为假时,才会执行表达式Z
            start, end = (1, 10) if start <= 0 else (start, end)
            start, end = (end-10, actual_pages) if end >= actual_pages else (start, end)
    
            pages_list = []
    
            # 首页标签
            first_page = '<a href="%s/1">首页</a>' % base_url
            # 上一页标签
            prev_page = '<a href="%s/%s">上一页</a>' % (base_url, self.current_page - 1 if self.current_page > 1 else self.current_page )
    
            pages_list.append(first_page+prev_page)
            for _ in range(start, end + 1):
                if _ == self.current_page:
                    _str = '<a class="active" href="%s/%s">%s</a>' % (base_url, _, _)
                else:
                    _str = '<a href="%s/%s">%s</a>' % (base_url, _, _)
                pages_list.append(_str)
    
            # 下一页标签
            next_page = '<a href="%s/%s">下一页</a>' % (base_url, self.current_page + 1 if self.current_page < actual_pages else self.current_page)
            # 尾页标签
            last_page = '<a href="%s/%s">首页</a>' % (base_url, actual_pages)
            pages_list.append(next_page+last_page)
    
            # 跳转标签和输入框
            # 注意嵌套情况下引号的使用:onclick后的引号,其参数的引号
            # 注意js的形参不能是已占用的关键字this
            jump = """<input type='text'/><a onclick="Jump('%s',this);">跳转</a>""" % base_url
            script = """<script>
                function Jump(base_url, ths){
                    val = ths.previousElementSibling.value;
                    if(val.trim().length>0){
                        location.href=base_url + "/" + val;
                    }
                }
            </script>"""
            pages_list.append(jump+script)
    
            pages = ''.join(pages_list)
            return pages
    View Code

    HTML文件

    home -index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
        <style>
            .pages a{
                display:inline-block;
                padding:5px;
                margin:5px;
                background-color:yellow;
            }
            .pages .active {background-color:red;}
        </style>
    </head>
    <body>
        <h1>输入数据</h1>
        <form action="/index/{{ current_page }}" method="post">
            <input type="text" name="name">
            <input type="text" name="age">
            <input type="submit" value="提交">
        </form>
        <h1>展示数据</h1>
        <table border="1">
            <th>
                <tr>
                    <td>姓名</td>
                    <td>年龄</td>
                </tr>
            </th>
            <tbody>
                {% for item in info_list %}
                <tr>
                    <!--raw行就是一个XSS跨站脚本攻击的一个例子,本来tornado内部会对js脚本默认进行处理,避免脚本攻击‘-->
                    <!--如果加上raw的话,就会以输入的格式进行处理-->
                    <!--如:输入<script>alert(1);</script>-->
                    <!--提交后,渲染页面时,遇到这一行就会执行该代码-->
                    <!--使用toranado的默认方式就好-->
                    <!--<td>{% raw item['name'] %}</td>-->
                    <td>{{ item['name'] }}</td>
                    <td>{{ item['age'] }}</td>
                </tr>
                {% end %}
            </tbody>
        </table>
        <div class="pages">
            {% raw page_nums %}
        </div>
    </body>
    </html>
    主页面(动态分页)

    plates -form.html -layout.html

    <form>
        <!--模板导入-->
        <h1>Form To Be Included</h1>
        <input type="text"/>
        <input type="password"/>
        <input type="button">
        <input type="submit">
    </form>
    form.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>模板继承</title>
    </head>
    <style>
        *{color:white;}
        .pg-header{
            width:800px;
            height:200px;
            background-color:gray;
        }
        .pg-content{
            width:800px;
            height:500px;
            background-color:green;
        }
        .pg-footer{
            width:800px;
            height:100px;
            background-color:orange;
        }
    </style>
            {% block css %}{% end %}
    <body>
        <div class="pg-header"></div>
        <div class="pg-content">
            {% block body %}{% end %}
        </div>
        <div class="pg-footer"></div>
    <script> function MainPage(){alert("Layout");}</script>
    {% block js %}{% end %}
    </body>
    </html>
    layout.html

    extend -home.html -index.html(主要是为了应用模板文件,展示模板引擎的继承和导入)

    {% extends '../plates/layout.html' %}
    
    {% block css %}
        <style>a{color:yellow;}</style>
    {%  end  %}
    
    {% block body %}
        <h1>Home Page</h1>
        <a>Home page</a>
    {%  end  %}
    
    {% block js %}
        <script>
            alert("Home  page.");
        </script>
    {%  end  %}
    home.html
    {% extends '../plates/layout.html' %}
    
    {% block body %}
        <h1>Index Page</h1>
        <a>Index Page</a>
        {% include '../plates/form.html'%}
    {%  end  %}
    
    {% block css %}
        <style>
            a{color:black;}
        </style>
    {%  end  %}
    
    {% block js %}
        <script>
            alert("Index page.");
        </script>
    {%  end  %}
    index.html
  • 相关阅读:
    RPC的入门
    Https的实现原理
    Celery
    Flask信号
    Redis安装
    python之递归
    python之三元表达式和生成式
    python第十八天作业
    python之生成器
    python之迭代器
  • 原文地址:https://www.cnblogs.com/yifeixu/p/8028549.html
Copyright © 2020-2023  润新知