项目代码已托管到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 SQLAlchemyfrom flask import Flask#创建对象db = SQLAlchemy()#初始化def config_extensions(app):db.init_app(app)
app/config.py
import osclass Config():SQLALCHEMY_DATABASE_URI = 'mysql://root:666666@127.0.0.1:3306/race_flask'SQLALCHEMY_TRACK_MODIFICATIONS = TrueSQLALCHEMY_ECHO = True
app/init.py
def create_app(app_name):app = Flask(app_name)app.config.from_object(Config)config_extensions(app) #装配SQLAlchemy对象 dbreturn 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 dbclass 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 SQLAlchemyfrom flask import Flaskfrom 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_appfrom app.views import config_blueprintfrom flask_script import Managerfrom flask_migrate import MigrateCommandapp = 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_appapp = 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 dbdb.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 Servermanager.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] = countreturn 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
