项目结构参考重庆2020年巴渝工匠杯市赛题目、2019年重庆市h3c大数据挑战赛题目
项目代码已托管到github,地址见:https://github.com/ybqdren/BygjRace-DataShowChart
一、起步-新建项目
配置环境
1.新建Python项目 命名为01_MyFlaskTest
2.在Teminal中安装pipenv
pip install pipenv
3.创建当前项目空间的虚拟环境
pipenv install
4.激活虚拟环境
pipenv shell
在teminal中执行上述指令,会返现项目路径前出现'(虚拟环境名称)$'类似字段。
这表明Pipenv已经为我们的项目激活了虚拟环境的子shell,此时虚拟环境表示已经激活成功了
安装三方包
1.安装flask
pipenv install flask
2.安装flask-sqlalchemy
pipenv install flask-sqlalchemy
3,安装Jinja2
pipenv install jinja2
4.安装flask-mysqldb(sqlalchemy连接mysql数据库必须)
pipenv install mysqldb
5.安装flask-migrate
pipenv install flask-migrate
6.安装flask-script
pipenv install flask-script
7.安装SQLAlchemy
pipenv install SQLAlchemy
按照目录规范添加目录
如图:
二、开始编码
Flask实例对象准备
1.定义flask app实例创建工厂函数
app/_init_.py
def create_app(app_name):
app = Flask(app_name)
return app
2.在工厂函数中装配db
app/extensions.py
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
#创建对象
db = SQLAlchemy()
#初始化
def config_extensions(app):
db.init_app(app)
app/config.py
import os
class Config():
SQLALCHEMY_DATABASE_URI = 'mysql://root:666666@127.0.0.1:3306/race_flask'
SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLALCHEMY_ECHO = True
app/_init_.py
def create_app(app_name):
app = Flask(app_name)
app.config.from_object(Config)
config_extensions(app) #装配SQLAlchemy对象 db
return app
蓝图准备
1.创建蓝图实例对象
app/views/main.py
from flask import Blueprint
# 创建蓝图
main_print = Blueprint('main_print',__name__)
2.提供蓝本注册函数
app/veiws/main/_init_.py
from .main import main_print
# 封装
DEFAULT_BLUEPRINT = {
(main_print,'')
}
#蓝图注册
def config_blueprint(app):
for blueprint,prefix in DEFAULT_BLUEPRINT:
app.register_blueprint(blueprint,prefix=prefix)
前端页面准备
1.echarts文件构建下载
https://echarts.apache.org/zh/builder.html
2.前端显示页面准备
app/templates/main/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>数据可视化展示页面</title>
<script src="/static/js/echarts.min.js"></script>
</head>
<body>
</body>
</html>
3.蓝图中构建视图函数
app.views.main.py
from flask import render_template
@main_print.route('/index')
def index():
return render_template('/main/index.html')
三、数据与模型类
模型类
app/modles/tbl_video_game_sales.py
from app.extensions import db
class Tbl_Video_Game_Sales(db.Model):
__tablename__ = 't_video_game_sales'
Rank = db.Column(db.String(255),primary_key=True) #销售排名
Name = db.Column(db.String(255)) #游戏名称
Platform = db.Column(db.String(255)) #该游戏发布平台
Year = db.Column(db.Integer) #发布年份(1980-2016)
Genre = db.Column(db.String(255)) #游戏类型
Publisher = db.Column(db.String(255)) #出版公司
NA_Sales = db.Column(db.DECIMAL(255,2)) #北美区域销量(以百万为单位计数)
EU_Sales = db.Column(db.DECIMAL(255,2)) #欧美区域销量(以百位为单位计数)
JP_Sales = db.Column(db.DECIMAL(255,2)) #日本区域销量(以百位为单位计数)
Other_Sales = db.Column(db.DECIMAL(255,2)) #其他国家销量(以百位为单位计数)
Global_Sales = db.Column(db.DECIMAL(255,2)) #全球销量(以百位为单位计数)
app/models/_init_.py
from .tbl_video_game_sales import Tbl_Video_Game_Sales
数据迁移
1.创建迁移仓库
创建数据迁移对象
app/extensions.py
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
from flask_migrate import Migrate,MigrateCommand
#创建对象
db = SQLAlchemy()
migrate = Migrate()
#初始化
def config_extensions(app):
db.init_app(app)
migrate.init_app(app,db)
manager.py
from app import create_app
from app.views import config_blueprint
from flask_script import Manager
from flask_migrate import MigrateCommand
app = create_app('app')
config_blueprint(app)
manager = Manager(app)
manager.add_command('db',MigrateCommand)#使用 MigrateCommand类使用db命令附加
if __name__ == '__main__':
manager.run()
Terminal上输入
python manage.py db init
flask-migrate会为我们生成一个迁移文件夹
2.创建迁移脚本
python manage.py db migrate
使用migrate子命令可以自动生成迁移脚本
ORM模型映射
此处参考:https://flask-sqlalchemy.palletsprojects.com/en/2.x/contexts/
当前步骤在Python Console中完成
1.导入工厂函数创建Flask实例对象
from app import create_app
app = create_app('app')
2.设置应用上下文(重要!)
app.app_context().push()
如果此处不推送上下文,会报错:No application found. Either work inside a view function or push an application context.
3.导入实例化的SQLAlchemy对象db,并绑定app
from app.extensions import db
db.init_app(app)
此时查看db对象,就会发现已经成功绑定了flask实例对象,并成功读取到配置信息
4.导入orm模型类
from app.models import Tbl_Video_Game_Sales
5.执行db.create_all()指令
db.create_all()
db.session.commit()
6.测试orm模型映射是否成功
Tbl_Video_Game_Sales.query.all()[:2]
查询结果
四、数据可视化
建立页面模板 'base.html'
app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block head_title%}{% endblock head_title%}</title>
<script src="/static/js/echarts.min.js"></script>
<style>
#main{
width: 1000px;
height: 500px;
margin-left: auto;
margin-right: auto;
margin-top:20px;
}
#content-id{
text-align: center;
font-size: 30px;
padding-top: 20px;
}
</style>
</head>
{% block content%}
{% endblock content%}
</html>
导入模型类
from app.models import Tbl_Video_Game_Sales
开启调试模式
from flask_script import Server
manager.add_command("runserver",Server(use_debugger=True))
1.柱状图
柱形图 -> 同一对象不对维度份额比较
视图函数
@main_print.route('/charts/bar')
def charts_bar():
game_sale = Tbl_Video_Game_Sales.query.first()
return render_template('/main/bar-chart.html',game_sale = game_sale)
页面
{% extends 'base.html'%}
{% block head_title %}
数据可视化展示-柱状图
{% endblock head_title%}
{% block content %}
<body>
<div id="content-id">柱状图-bar</div>
<div id="main"></div>
<script type="text/javascript">
var barChart = echarts.init(document.getElementById('main'));
var option = {
title: {
text: '{{game_sale.Name}}各区域销量',
subtext: '单位:百万'
},
tooltip:{},
xAxis: {
data: ["北美","欧美","日本","其他国家"]
},
yAxis: {
type:'value'
},
series: [{
name: '销量',
type: 'bar',
data: [{{game_sale.NA_Sales}}, {{game_sale.EU_Sales}}, {{game_sale.jp_Sales}}, {{game_sale.Other_Sales}}]
}]
};
barChart.setOption(option);
</script>
</body>
{% endblock content %}
2.折线图
数据i变化趋势
视图函数
@main_print.route('/charts/line')
def charts_line():
game = dict()
for y in range(1999,2011,1):
count = Tbl_Video_Game_Sales.query.filter(Tbl_Video_Game_Sales.Year == y).count()
game[y] = count
return render_template('/main/line-chart.html',game = game)
页面
{% extends 'base.html'%}
{% block head_title%}
数据可视化展示-折线图
{% endblock %}
{% block content %}
<body>
<div id="content-id">折线图-line</div>
<div id="main"></div>
</body>
<script>
var line_chart = echarts.init(document.getElementById('main'));
var option = {
title:{
text:'2000年~2010年发行游戏数量增长趋势',
subtext:'单位:个'
},
tooltip:{},
xAxis:{
type:'category',
data:[{%for g in game%}'{{ g }}',{% endfor %}]
},
yAxis:{},
series:[{
type:'line',
data:[{% for g in game%}{{game[g]}},{% endfor %}]
}]
};
line_chart.setOption(option);
</script>
{% endblock %}
3.双图表切换(折线/柱)
视图函数
@main_print.route('/charts/changeView')
def change_View():
game_sale = Tbl_Video_Game_Sales.query.order_by(Tbl_Video_Game_Sales.Global_Sales.desc()).first()
return render_template('/main/changeView-chart.html',game_sale = game_sale)
页面
{% extends 'base.html' %}
{% block head_title%}
图像切换-折线图/柱状图
{% endblock head_title%}
{% block content %}
<body>
<div id="content-id">折线图/柱形图-line/bar</div>
<div id="main"></div>
</body>
<script>
my_chart = echarts.init(document.getElementById('main'));
var option = {
title:{
text:'一个简单的折/柱切换图',
},
tooltip:{
trigger:'item'
},
toolbox:{
feature:{
magicType:{
type:['line','bar']
}
}
},
xAxis:{
type:'category',
data:["北美","欧美","日本","其他国家"]
},
yAxis: {},
series:[{
type:'line',
data: [{{game_sale.NA_Sales}}, {{game_sale.EU_Sales}}, {{game_sale.jp_Sales|default('3.5')}}, {{game_sale.Other_Sales}}]
}]
};
my_chart.setOption(option);
</script>
{% endblock content %}
4.雷达图
多维度数据展示
视图函数
@main_print.route('/charts/radar')
def charts_radar():
game = Tbl_Video_Game_Sales.query.filter(Tbl_Video_Game_Sales.Platform == 'Wii').all()[:3]
return render_template('/main/radar-chart.html',game = game)
页面
{% extends 'base.html'%}
{% block head_title %}
数据可视化展示-雷达图
{% endblock head_title %}
{% block content %}
<body>
<div id="content-id">雷达图-radar</div>
<div id="main"></div>
<script>
var na_sales = [{% for g in game%}{{ g.NA_Sales }},{% endfor %}]; //北美地区销量
var eu_sales = [{% for g in game %}{{ g.EU_Sales }},{% endfor %}]; //欧美地区销量
var jp_sales = [{% for g in game %}{{ g.JP_Sales }},{% endfor %}]; //日本地区销量
var other_sales = [{% for g in game%}{{ g.Other_Sales }},{% endfor %}]; //其他地区销量
var radar_chart = echarts.init(document.getElementById('main'));
var option = {
title:{
text:'各区域销量'
},
tooltip:{},
legend:{
data:[{% for g in game %}'{{ g.Name }}',{% endfor %}],
},
radar:{
indicator:[
{name:'北美',max:50},
{name:'欧洲',max:50},
{name:'日本',max:50},
{name:'其他',max:50}
]
},
series: [{
type:'radar',
data:[
{% for g in game%}
{
value:[na_sales[{{ loop.index }}-1],eu_sales[{{ loop.index }}-1],jp_sales[{{ loop.index }}-1],other_sales[{{ loop.index }}-1]],
name:'{{ g.Name }}'
},
{% endfor %}
]
}]
};
radar_chart.setOption(option);
</script>
</body>
{% endblock content %}
5.饼图
同一对象组成展示
视图函数
@main_print.route('/charts/pie')
def charts_pie():
game = Tbl_Video_Game_Sales.query.filter(Tbl_Video_Game_Sales.Platform == 'PS3').order_by(Tbl_Video_Game_Sales.Global_Sales.desc()).all()[:10]
return render_template('/main/pie-chart.html',game = game)
页面
{% extends 'base.html' %}
{% block head_title%}
数据可视化展示-饼图
{% endblock head_title%}
{% block content %}
<body>
<div id="content-id">饼图-pie</div>
<div id="main"></div>
<script>
var na_sales = [{% for g in game %}{{ g.NA_Sales}},{% endfor %}];
var eu_sales = [{% for g in game %}{{g.EU_Sales}},{% endfor %}];
var jp_sales = [{% for g in game %}{{g.JP_Sales}},{% endfor %}];
var other_sales = [{% for g in game %}{{g.Other_Sales}},{% endfor %}];
var avg_na =eval( na_sales.join("+"));
var avg_eu = eval(eu_sales.join("+"));
var avg_jp = eval(jp_sales.join("+"));
var avg_other = eval(other_sales.join("+"));
var pie_chart = echarts.init(document.getElementById('main'));
var option = {
title:{
text:'PS3平台游戏销量区域份额',
subtext:'摘取销量前十游戏数据'
},
tooltip:{
formatter:'【{b}区域销量】 <br/> {c}百万份({d}%)'
},
legend:{
data:['北欧','欧洲','日本','其他']
},
series:[
{
type:'pie',
radius:['25%','50%'],
data:[
{value:avg_na,name:'北欧'},
{value:avg_eu,name:'欧洲'},
{value:avg_jp,name:'日本'},
{value:avg_other,name:'其他'}
]
}
]
};
pie_chart.setOption(option);
</script>
</body>
{% endblock content %}
6.南丁格尔图(玫瑰图)
比饼图更直观
视图函数
@main_print.route('/charts/rosePie')
def charts_rosePie():
game = Tbl_Video_Game_Sales.query.filter(Tbl_Video_Game_Sales.Platform == 'PS3').order_by(Tbl_Video_Game_Sales.Global_Sales.desc()).all()[:10]
return render_template('/main/rosePie-chart.html',game = game)
页面
{% extends 'base.html' %}
{% block head_title%}
数据可视化展示-南丁格尔图
{% endblock head_title%}
{% block content %}
<body>
<div id="content-id">南丁格尔图-rosePie</div>
<div id="main"></div>
<script>
var na_sales = [{% for g in game %}{{ g.NA_Sales}},{% endfor %}];
var eu_sales = [{% for g in game %}{{g.EU_Sales}},{% endfor %}];
var jp_sales = [{% for g in game %}{{g.JP_Sales}},{% endfor %}];
var other_sales = [{% for g in game %}{{g.Other_Sales}},{% endfor %}];
var avg_na =eval( na_sales.join("+"));
var avg_eu = eval(eu_sales.join("+"));
var avg_jp = eval(jp_sales.join("+"));
var avg_other = eval(other_sales.join("+"));
var pie_chart = echarts.init(document.getElementById('main'));
var option = {
title:{
text:'PS3平台游戏销量区域份额',
subtext:'摘取销量前十游戏数据'
},
tooltip:{
formatter:'【{b}区域销量】 <br/> {c}百万份({d}%)'
},
legend:{
data:['北欧','欧洲','日本','其他']
},
series:[
{
type:'pie',
radius:['25%','50%'],
data:[
{value:avg_na,name:'北欧'},
{value:avg_eu,name:'欧洲'},
{value:avg_jp,name:'日本'},
{value:avg_other,name:'其他'}
],
roseType:'radius' //area
}
]
};
pie_chart.setOption(option);
</script>
</body>
{% endblock content %}
项目启动
python manage.py runserver