Tornado + Bootstrap quickly build their own web applications

Foreword

Recently with python tordado framework, a whole page template, for displaying and publishing data access,

tornado easy to use, bootstrap more popular, it is also easy use, and together do small case very quickly.


Technical reserves

  1. python

    Basic knowledge of object-oriented encapsulation, inheritance

  2. database

    mysql

  3. frame

    tornado, sqlalchemy (ORM), template

  4. development tools

    pycharm, chrome


function development

A. Requirements Analysis

  1. Statistics show per page 5, in reverse order by date

    When there is no statistical data, there must be text prompts: "temporary no docking statistics"

  2. Support query by date

    Does not display pagination query

  3. Support paging query, suggesting the current page number is located, you can jump to any page


II. Page Prototype

Limited front-end personal level, to get such a page from scratch estimates have to spend half a day, so look for the bootstrap template, inside there are a lot of ready-made components can be used directly, and then change the next layout, tone down the style, do a simple page is sufficient.

bootstrap : https://v3.bootcss.com/components/


III. Framework to build tornado

The students are familiar with python, direct easy_install or pip install the latest tornado, sqlalchemy, pymysql modules

bootstrap.js directly to the official website to download on the line, of course, also need to bootstrap dependent JQuery.js

app.py

Configure a static resource path:

"static_path": os.path.join(os.path.dirname(__file__), "statics"),

Configuration template path:

"template_path": os.path.join(os.path.dirname(__file__), 'templates'),

Configure the operating mode:

# 通过脚本传参的方式指定
define("debug", default=1, help="debug mode: 1 to open, 2 to test env, other to production")
"debug": bool(options.debug),

Development, debugging mode, open the single-process:

application.listen(options.port)
tornado.ioloop.IOLoop.instance().start()

Production mode, open multi-process:

application.bind(options.port)
application.start(3)  # 开启 3 个进程
tornado.ioloop.IOLoop.instance().start()


IV. Mysql connection

Acquired DBSession class, where you want to use, create objects [session = DBSession ()] can be,

If the database is not particularly ordinary operation, the session recovery time period can be set a little longer, for example: pool_recycle = 60

# coding: utf-8
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from settings.setting import MYSQL_SERVER, MYSQL_DRIVER, MYSQL_USERNAME, MYSQL_PASSWORD, DB_NAME, DB_CHARSET

# MYSQL_USERNAME = os.getenv('MYSQL_USER') or settings.MYSQL_USERNAME
# MYSQL_PASSWORD =

# 数据库
engine = create_engine("mysql+{driver}://{username}:{password}@{server}/{database}?charset={charset}"
                       .format(driver=MYSQL_DRIVER,
                               username=MYSQL_USERNAME,
                               password=MYSQL_PASSWORD,
                               server=MYSQL_SERVER,
                               database=DB_NAME,
                               charset=DB_CHARSET),
                       pool_size=20,
                       max_overflow=100,
                       pool_recycle=1,
                       echo=False)
engine.execute("SET NAMES {charset};".format(charset=DB_CHARSET))
MapBase = declarative_base(bind=engine)
DBSession = sessionmaker(bind=engine)


V. processing class

Base class defines the API specifications and methods common tools

First base class encapsulates GlobalBaseHandler, database session, and the method of acquisition parameters package

# 全局基类方法
class GlobalBaseHandler(BaseHandler):
    @property
    def session(self):
        if hasattr(self, "_session"):
            return self._session
        self._session = DBSession()
        return self._session

    # 关闭数据库会话
    def on_finish(self):
        if hasattr(self, "_session"):
            self._session.close()

    def prepare(self):
        pass


Inquiry, paging business processing class

Note that: (less than a first case); (larger than the total number of pages, but the total number of pages is zero).

class IllegalStats(GlobalBaseHandler):
    def get(self):
        """
        获取接入,发布统计数据
        :return:
        """
        date = self.get_argument("date")
        current_page = self.get_argument("current_page")  # 当前页
        if date:
            return self.query_by_date(date)
        elif current_page:
            return self.query_paginate(current_page)
        # 默认返回第一页的数据
        else:
            return self.query_paginate()

    def query_paginate(self, current_page=None):
        if current_page is None:
            current_page = 1
        else:
            current_page = int(current_page)
        #
        page_size = 5  # 分页条数
        # 总记录数, 总页数
        total_count = IllegalAccessStats.query_count(self.session)
        if total_count % page_size == 0:
            total_page = int(total_count / page_size)
        else:
            total_page = int(total_count / page_size) + 1

        # 小于第一页
        if current_page <= 0:
            current_page = 1
        # 大于最后一页
        if total_page > 0:
            if current_page > total_page:
                current_page = total_page
        else:
            current_page = 1

        # 当前页的数据
        stats_list = IllegalAccessStats.query_paginate(self.session, current_page=current_page, page_size=page_size)
        return self.render("statistics.html", stats_list=stats_list, date="", total_count=total_count, total_page=total_page, current_page=current_page)

    def query_by_date(self, date):
        stats_list = IllegalAccessStats.query_by_date(self.session, date=date)
        #
        return self.render("statistics.html", stats_list=stats_list, date=date, total_count=None, total_page=None, current_page=None)


VI. Rendering Templates

template, that is, to write python inside html codes, if judged, for range and python syntax statement exactly the same, there is not much difficulty, came out slowly debugging, error prompt template rendering very detailed, very good debugging,

Feeling sick to write a thief, but also a label, but also a logical process.

statistics.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- viewport视口:网页可以根据设置的宽度自动进行适配,在浏览器的内部虚拟一个容器,容器的宽度与设备的宽度相同。
    width: 默认宽度与设备的宽度相同
    initial-scale: 初始的缩放比,为1:1 -->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>接入&发布统计信息</title>
    <!-- Bootstrap -->
    <link href="{{static_url('css/bootstrap.min.css')}}" rel="stylesheet">
    <script src="{{static_url('js/jquery-2.1.0.min.js')}}"></script>
    <script src="{{static_url('js/bootstrap.min.js')}}"></script>
    <style type="text/css">
        th, td {
            text-align: center;
            height: 50px;
            vertical-align:middle;
        }
    </style>
</head>
<body>
<div class="container">
    <h2 style="text-align: center">接入 & 发布统计信息</h2>
    <br>
    <br>

    <div style="float: left;">
        <form class="form-inline" action="/illegal/stats" method="get">
            <div class="form-group">
                <label for="exampleInputName1">日期</label>
                <input type="text" name="date" value="{{ date }}" class="form-control" id="exampleInputName1" placeholder="yyyy-mm-dd" >
            </div>
            <button type="submit" class="btn btn-default" style="margin: 5px;">查询</button>
        </form>
    </div>

    <br>
    <br>
    <br>
    <br>
    <br>
    <table border="1" class="table table-bordered table-hover">
        <div>
            <a class="btn btn-primary" href="/illegal/stats?" style="float: left; margin: 3px;">接入</a>
            <a class="btn btn-primary" href="/illegal/stats?" style="position: relative; left: 872px; margin: 3px">发布</a>
        </div>

        <tr class="access">
            <th style="background: #f8efc0; vertical-align:middle">日期</th>
            <th style="background: #4cae4c; vertical-align:middle">违法接收</th>
            <th style="background: #4cae4c; vertical-align:middle">入库成功</th>
            <th style="vertical-align: middle">读取成功</th>
            <th style="background: #d9534f; vertical-align:middle">读取失败</th>
            <th style="vertical-align: middle">下载成功</th>
            <th style="background: #d9534f; vertical-align:middle">下载失败</th>
            <th style="vertical-align: middle">写入成功</th>
            <th style="background: #d9534f; vertical-align:middle">写入失败</th>
            <th style="background: #4cae4c; vertical-align:middle">审核接收</th>
            <th style="background: #4cae4c; vertical-align:middle">发布成功</th>
        </tr>


        {% if len(stats_list) > 0 %}
            {% for stats in stats_list %}
                <tr>
                <td style="vertical-align: middle">{{ stats["date"] }}</td>
                <td style="vertical-align: middle">{{ stats["access_received_total"] }}</td>
                <td style="vertical-align: middle">{{ stats["access_inserted_total"] }}</td>
                <td style="vertical-align: middle">{{ stats["read_success_total"] }}</td>
                <td style="vertical-align: middle">{{ stats["read_false_total"] }}</td>
                <td style="vertical-align: middle">{{ stats["download_success_total"] }}</td>
                <td style="vertical-align: middle">{{ stats["download_false_total"] }}</td>
                <td style="vertical-align: middle">{{ stats["write_success_total"] }}</td>
                <td style="vertical-align: middle">{{ stats["write_false_total"] }}</td>
                <td style="vertical-align: middle">{{ stats["publish_received_total"] }}</td>
                <td style="vertical-align: middle">{{ stats["publish_send_total"] }}</td>
                </tr>
            {% end %}
        {% else %}
            <tr>
                <td colspan="11" style="vertical-align: middle">暂没有对接统计信息</td>
            </tr>
        {% end %}

        </table>

<!--    查询的时候不显示分页内容-->
    {% if total_count is not None or total_page is not None %}
        <div>
            <nav aria-label="Page navigation">
                <ul class="pagination">
                    {% if current_page == 1 %}
                        <li class="disabled">
                    {% end %}

                    {% if current_page != 1 %}
                        <li>
                    {% end %}
                            <a href="/illegal/stats?current_page={{current_page - 1}}" aria-label="Previous">
                                <span aria-hidden="false">&laquo;</span>
                            </a>
                        </li>

                    {% for page in range(1, total_page + 1) %}
                        {% if current_page == page %}
                            <li class="active"><a href="/illegal/stats?current_page={{ page }}">{{ page }}</a></li>

                        {% end %}
                        {% if current_page != page %}
                            <li><a href="/illegal/stats?current_page={{ page }}">{{ page }}</a></li>

                        {% end %}

                    {% end %}

                    {% if current_page == total_page or current_page == 1 %}
                        <li class="disabled">
                    {% end %}

                    {% if current_page != total_page and current_page != 1 %}
                        <li>
                    {% end %}
                        <a href="/illegal/stats?current_page={{current_page + 1}}" aria-label="Next">
                            <span aria-hidden="true">&raquo;</span>
                        </a>
                    </li>
                    <span style="font-size: 25px;margin-left: 5px;">
                            共{{ total_count }}条记录,共{{ total_page }}页
                    </span>
                </ul>
            </nav>
        </div>
    {% end %}
</div>
</body>
</html>


Needs attention

  1. Template rendering time, use the static_url()function to get the static resources (statics) path, otherwise the template will not find the css, js files, can not load the page properly.

    <link href="{{static_url('css/bootstrap.min.css')}}" rel="stylesheet">

    <script src="{{static_url('js/jquery-2.1.0.min.js')}}"></script>

    <script src="{{static_url('js/bootstrap.min.js')}}"></script>


  1. Adding to the current activation status page


Improved project

xxx


Finally, the project web address: https://github.com/kaichenkai/TornadoWebApp


ending ~


Guess you like

Origin www.cnblogs.com/kaichenkai/p/11999880.html