前言

最近用 python tordado 框架, 整了一个模板页面, 用于接入与发布数据的展示,

tornado 简单易用, bootstrap 比较流行, 用起来也省事, 配合起来做些小案例非常迅速.

技术储备

  1. python

    基础知识, 面向对象封装,继承

  2. 数据库

    mysql

  3. 框架

    tornado, sqlalchemy (ORM), template

  4. 开发工具

    pycharm, chrome

功能开发

一. 需求分析

  1. 每页展示 5 条统计数据, 按日期倒序排列

    没有统计数据时, 要有文字提示: "暂没有对接统计信息"

  2. 支持按日期进行查询

    查询时不显示分页情况

  3. 支持分页查询, 提示目前所在页码, 可跳转到任意一页

二. 页面原型

个人前端水平有限, 弄这样一个页面从无到有估计得花半天时间, 所以就找了 bootstrap 的模板, 里边有很多现成的组件可以直接使用, 然后改下布局, 调下样式, 做一个简单的页面足够.

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

三. 搭建 tornado 框架

熟悉 python 的同学, 直接 easy_install 或者 pip 安装最新的 tornado, sqlalchemy, pymysql 等模块

bootstrap.js 直接到官网下载就行, 当然还需要 bootstrap 依赖的 JQuery.js

app.py

配置静态资源路径:

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

配置模板路径:

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

配置运行模式:

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

开发, 调试模式, 开启单进程:

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

生产模式, 开启多进程:

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

四. 连接 mysql

获取了DBSession 类, 在需要使用的地方, 创建对象[ session = DBSession() ]即可,

如果数据库操作不是特别平凡, 会话回收的时间周期可以设置的长一点, 例如: 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)

五. 处理类

基础类, 定义了一些 API 规范和常用的工具方法

先封装了基础类 GlobalBaseHandler , 数据库会话和获取参数的方法封装

# 全局基类方法
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

查询, 分页业务处理类

需要注意的是: (小于第1页情况); (大于总页数的情况, 但总页数为 0 的情况).

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)

六. 模板渲染

template, 就是在 html 里边写 python 代码, if 判断, for range 语句和python语法一模一样, 没有太大难度, 慢慢调试就出来了, 模板渲染报错提示非常详细, 很好调试,

感觉写起来贼恶心, 又是标签, 又是逻辑处理.

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>

需要注意的地方

  1. 模板渲染的时候, 需要使用 static_url() 函数获取静态资源( statics ) 的路径, 不然模板会找不到 css, js 文件, 不能正常加载页面.

    <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. 给当前页添加激活状态

项目改进

xxx

最后给出web项目地址: https://github.com/kaichenkai/TornadoWebApp

ending ~

Tornado + Bootstrap 快速搭建自己的web应用的更多相关文章

  1. 基于ASP.NET Core 3.0快速搭建Razor Pages Web应用

    前言 虽然说学习新的开发框架是一项巨大的投资,但是作为一个开发人员,不断学习新的技术并快速上手是我们应该掌握的技能,甚至是一个.NET Framework开发人员,学习.NET Core 新框架可以更 ...

  2. 利用Bootstrap快速搭建个人响应式主页(附演示+源码)

    1.前言 我们每个程序员都渴望搭建自己的技术博客平台与他人进行交流分享,但使用别人的博客模板没有创意.做网站后台的开发人员可能了解前端,可是自己写一个不错的前端还是很费事的.幸好我们有Bootstra ...

  3. bootstrap快速搭建属于自己的后台模板库

    不论做什么项目,我们都以快速搭建为主,设计师固然重要,但是,我们前端开发的也必须能给出自己以前做过什么样的模板,自己收藏的模板,或者我们弹框的形式,我的提示框的形式,我用的下拉框的插件,日历的插件,我 ...

  4. Laravel-Easy-Admin 快速搭建数据后台 web管理后台

    基于PHP + Laravel + element-admin-ui 搭建的快速数据后台,只在解决系列后台增删改查等日常操作.快速搭建,在生成业务的同时可以花更多的时间关注技术本身,提高程序员自身进阶 ...

  5. 前端框架Bootstrap - 快速搭建网站

    Bootstrap简介         Bootstrap是Twitter推出的一个开源的用于前端开发的工具包.是一个CSS/HTML/JavaScript框架.Bootstrap是基于HTML5和C ...

  6. tornado+bootstrap急速搭建你自己的网站

    bootstrap既然是这么的流行又能省很多的事为什么不用他呢?再加上牛X的produced by FB的tornado简直如虎添翼了! 1. 安装配置 安装所需要的库等内容.这里没什么需要多讲的.t ...

  7. 快速搭建Web环境 Angularjs + Express3 + Bootstrap3

    快速搭建Web环境 Angularjs + Express3 + Bootstrap3 AngularJS体验式编程系列文章, 将介绍如何用angularjs构建一个强大的web前端系统.angula ...

  8. windows下如何快速搭建web.py开发框架

    在windows下如何快速搭建web.py开发框架 用Python进行web开发的话有很多框架供选择,比如最出名的Django,tornado等,除了这些框架之外,有一个轻量级的框架使用起来也是非常方 ...

  9. 在windows下如何快速搭建web.py开发框架

    在windows下如何快速搭建web.py开发框架 用Python进行web开发的话有很多框架供选择,比如最出名的Django,tornado等,除了这些框架之外,有一个轻量级的框架使用起来也是非常方 ...

随机推荐

  1. Java设计模式之builder模式

    Java设计模式之builder模式 今天学mybatis的时候,知道了SQLSessionFactory使用的是builder模式来生成的.再次整理一下什么是builder模式以及应用场景. 1. ...

  2. enable device: BAR 0 [mem 0x00000000-0x003fffff] not claimed

    /******************************************************************************* * enable device: BA ...

  3. 修改jar包中的文件

    1.用WinRAR压缩软件打开jar包 2.将修改过的文件直接拖拽并覆盖被替换的文件即可

  4. mac下使用java测试iOS推送

    首先mac下有很多现在的测试iOS推送软件,为什么要用java程序测试呢: 因为大多数后台推送服务可能是JAVA开发的,那么为了验证我们在MAC上导出的推送证书文件是否正确: 制作开发证书的iOS开发 ...

  5. Ubuntu 安装最新版 (1.12) Golang 并使用 go mod

    wget https://dl.google.com/go/go1.12.4.linux-amd64.tar.gz sudo tar -zxvf go1.12.4.linux-amd64.tar.gz ...

  6. Oracle 如何恢复删除并提交的表数据

    在Oracle的数据库中,如果不小心删除数据,该如何恢复数据呢? 有两种方法 :scn 方法和时间戳方法 一.恢复删除数据的SQL语法(建议用时间戳) 1.通过scn恢复删除且已提交的数据 1)获得当 ...

  7. response.redirect 正在中止线程

    问题描述:正在中止线程问题原因:Response.End 方法终止页的执行,并将此执行切换到应用程序的事件管线中的 Application_EndRequest 事件.不执行 Response.End ...

  8. 小米手机root

    目录 概念 解锁流程 root流程 如何Root? 关于supersu 关于twrp 关于Magisk Manager ref: 申请开发板流程 线刷教程 小米手机root 概念 解锁: 使手机可以刷 ...

  9. Data Flow ORB-SLAM for Real-Time Performance on Embedded GPU Boards

    张宁 Data Flow ORB-SLAM for Real-Time Performance on Embedded GPU Boards 数据流ORB-SLAM可在嵌入式GPU板上实现实时性能链接 ...

  10. SAP翔子_ABAP_DEMO篇索引

    序号 描述 SAP翔子_ABAP_DEMO篇1 ABAP DEMO篇1 单层反查BOM SAP翔子_ABAP_DEMO篇2 ABAP DEMO篇2 删除工艺路线 SAP翔子_ABAP_DEMO篇3 A ...