Flask

Flask简介

Flask作为Web框架,它的作用主要是为了开发Web应用程序。那么我们首先来了解下Web应用程序。Web应用程序 (World Wide Web)诞生最初的目的,是为了利用互联网交流工作文档。

一切从客户端发起请求开始。
所有Flask程序都必须创建一个程序实例。
当客户端想要获取资源时,一般会通过浏览器发起HTTP请求。
此时,Web服务器使用一种名为WEB服务器网关接口的WSGI(Web Server Gateway Interface)协议,把来自客户端的请求都交给Flask程序实例。
Flask使用Werkzeug来做路由分发(URL请求和视图函数之间的对应关系)。根据每个URL请求,找到具体的视图函数。
在Flask程序中,路由一般是通过程序实例的装饰器实现。通过调用视图函数,获取到数据后,把数据传入HTML模板文件中,模板引擎负责渲染HTTP响应数据,然后由Flask返回响应数据给浏览器,最后浏览器显示返回的结果。

Flask诞生于2010年,是Armin ronacher(人名)用Python语言基于Werkzeug工具箱编写的轻量级Web开发框架。它主要面向需求简单的小应用。
Flask本身相当于一个内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证FlaskLogin),都需要用第三方的扩展来实现。比如可以用Flask-extension加入ORM、窗体验证工具,文件上传、身份验证等。Flask没有默认使用的数据库,你可以选择MySQL,也可以用NoSQL。其 WSGI 工具箱采用 Werkzeug(路由模块) ,模板引擎则使用 Jinja2 。可以说Flask框架的核心就是Werkzeug和Jinja2。
Python最出名的框架要数Django,此外还有Flask、Tornado等框架。虽然Flask不是最出名的框架,但
是Flask应该算是最灵活的框架之一,这也是Flask受到广大开发者喜爱的原因。

Flask扩展包:

  • Flask-SQLalchemy:操作数据库;
  • Flask-migrate:管理迁移数据库;
  • Flask-Mail:邮件;
  • Flask-WTF:表单;
  • Flask-script:插入脚本;
  • Flask-Login:认证用户状态;
  • Flask-RESTful:开发REST API的工具;
  • Flask-Bootstrap:集成前端Twitter Bootstrap框架;
  • Flask-Moment:本地化日期和时间;

Flask基本使用

Hello World 程序

from flask import Flask
# Flask类接收一个参数__name__
app = Flask(__name__)

# 路由解析通过用户访问的路径,匹配相应的函数
# 装饰器的作用是将路由映射到视图函数index
@app.route("/")
def index():
    return "hello,world"
# Flask应用程序实例的run方法启动WEB服务器
if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0",port=3000)   #   debug 开启调试,更改代码内容,界面相应改变;
                                                    #   host改成0.0.0.0让其他机器可以访问
                                                    #   port=3000端口号

路由传参

有时我们需要将同一类URL映射到同一个视图函数处理,比如:使用同一个视图函数 来显示不同用户的个人信息。
通过向规则参数添加变量部分,可以动态构建URL。此变量部分标记为。它作为关键字参数传递给与规则相关联的函数。

from flask import Flask

app = Flask(__name__)

@app.route("/index")
def index():
    return "hello,world"

# 通过访问路径获取用户的字符串参数
@app.route("/user/<name>")  # <name>表示name参数,需要将路径中的name参数传入下面的函数中
def Wellcome(name):
    return "你好%s"%name

# 通过访问路径获取用户的整形参数
# 路由传递的参数默认当做string处理,这里指定int,尖括号中冒号后面的内容是动态的
# 除此之外还有 float 型
@app.route("/user/<int:id>")
def Wellcome1(id):
    return "你好%d号会员"%id

# 路由的路径不能重复,用户通过唯一路径访问特定函数

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0",port=3000)

使用 render_template 渲染界面

上面的函数中可以 return HTML语句,达到渲染界面的效果,但这样做对于不方便可以使用 render_template 。首先从 flask 中导入 render_template 。在 同级目录下建立 templates 文件夹,在这个文件夹中创建一个 HTML 程序,取名 index.html 。在 index 函数中使用 return render_template('index.html') 就可以将写入相应的 HTML 程序在界面中渲染。

源代码如下:

from flask import Flask,render_template

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0",port=3000)

HTML程序如下:

<html>
    <head>
    </head>
    <body>
        <h1>hello world</h1>
    </body>
</html>

利用循环和判断语句控制 template 渲染

使用 if 判断

HTML 程序中使用 if 判断,如下所示,其意义是当传入了 title 变量就是用传入的 title 变量,否则使用默认,此处默认设置的是 Flask App

{% if title %}
    <title>{{title}}</title> <!-- {{title}}变量传入此处 -->
{% else %}
    <title>Flask App</title>
{% endif %}

当不传入参数时,网页名字就会变成 Flask App

@app.route('/')
def index():
    return render_template('index.html')

传入参数时,网页名字会使用传入的名字 Home

@app.route('/')
def index():
    return render_template('index.html', title='Home')

源代码如下:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0",port=3000)   #   debug 开启调试,更改代码内容,界面相应改变;
                                                    #   host改成0.0.0.0让其他机器可以访问
                                                    #   port=3000端口号

HTML 程序如下:

<html>
    <head>
        {% if title %}
        <title>{{title}}</title> <!-- {{title}}变量传入此处 -->
        {% else %}
        <title>Flask App</title>
        {% endif %}
    </head>
    <body>
        <h1>hello world</h1>
    </body>
</html>

使用循环

循环的基本语法如下,其意义是将 data 变量中的内容放到p标签中

{% for p in data %}
    <p> {{p}} </p>    
{% endfor %}

同样的需要传入 data 变量如下所示

@app.route('/')
def index():
    paragraph=[
        'section 1',
        'section 2',
        'section 3'
    ]
    return render_template('index.html',title='Home',data=paragraph)

显示结果效果如下

源代码如下:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    paragraph=[
        'section 1',
        'section 2',
        'section 3'
    ]
    return render_template('index.html',title='Home',data=paragraph)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0",port=3000)   #   debug 开启调试,更改代码内容,界面相应改变;
                                                    #   host改成0.0.0.0让其他机器可以访问
                                                    #   port=3000端口号

HTML 程序如下:

<html>
    <head>
        {% if title %}
        <title>{{title}}</title> <!-- {{title}}变量传入此处 -->
        {% else %}
        <title>Flask App</title>
        {% endif %}
    </head>
    <body>
        <h1>hello world</h1>

        {% for p in data %}
            <p> {{p}} </p>
        {% endfor %}
    </body>
</html>

向页面传递一个变量

值得注意的是,我们可以向 HTML 中传入变量。在 render_template 函数中自定义title变量,如:render_template('index.html',title=title) 。向 render_template 定义 title 变量后,需要在 HTML 中接收该变量。使用两个大括号,在两个大括号中间写入 title{{title}} ,这样就实现向 HTML 传入变量。

传递普通变量

from flask import Flask,render_template

app = Flask(__name__)

@app.route("/")
def index():
    title = "Flak App"  #普通变量
    return render_template("index.html",title=title)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0",port=3000)

HTML程序如下:

<html>
    <head>
        <title>{{title}}</title>    <!-- {{title}}变量传入此处 -->
    </head>
    <body>
        <h1>hello world</h1>
    </body>
</html>

传递列表

传递列表如何显示呢?可以用到上面讲的for循环

from flask import Flask,render_template

app = Flask(__name__)

@app.route("/")
def index():
    title = "Flak App"  #普通变量
    name = ["小张","小赵","小王"]   #列表
    return render_template("index.html",title=title,name=name)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0",port=3000)

HTML程序如下:

<html>
    <head>
        <title>{{title}}</title>    <!-- {{title}}变量传入此处 -->
    </head>
    <body>
        <h1>hello world</h1>

        今天值班的有:<br/>
        {%for n in name%}
            <li>{{n}}</li>
        {%endfor%}
    </body>
</html>

传递字典

from flask import Flask,render_template

app = Flask(__name__)

@app.route("/")
def index():
    title = "Flak App"  #普通变量
    name = ["小张","小赵","小王"]   #列表
    task = {"任务":"打扫卫生","时间":"3小时"}
    return render_template("index.html",title=title,name=name,task=task)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0",port=3000)

HTML程序如下:

<html>
    <head>
        <title>{{title}}</title>    <!-- {{title}}变量传入此处 -->
    </head>
    <body>
        <h1>hello world</h1>

        今天值班的有:<br/>
        {%for n in name%}
            <li>{{n}}</li>
        {%endfor%}

        <br/>

        <table border="1">
            {% for key,value in task.items()%}  <!-- 使用task.items()方法,将字典变成[( , ),( , ),( , )]形式 -->
            <tr>
                <td>{{key}}</td>
                <td>{{value}}</td>
            </tr>
            {%endfor%}
        </table>
    </body>
</html>

模板的继承和引用

模板继承和修改

模板中有很多共用的部分,我们可以把共用的部分写在一个文件中,可简化代码。
模板的继承,首先创建 base.html 写入一些内容

<html>
    <head>
        {% if title %}
        <title>{{title}}</title>
        {% else %}
        <title>Flask App</title>
        {% endif %}
    </head>
    <body>
        <h3><a href="/">Flask App</a></h3>
        <hr>
    </body>
</html>

index.html 中使用关键字 extends 继承模板

{% extends 'base.html' %}

有时会将继承的模板里面的内容进行更改,可以使用 block 语句

{% block content %}
    <h1>parent template</h1> <!-- 可能要修改的内容 -->
{% endblock %}

content 为该block的名字

然后在 index.html 中同样使用上面的语句,对模板中的 block 里面的内容修改,如果不修改,就是原来 block 块中的内容

{% block content %}
    {% for p in data %}
        <p>{{p}}</p>
    {% endfor %}
{% endblock %}

源代码如下:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    paragraph=[
        'section 1',
        'section 2',
        'section 3'
    ]
    return render_template('index.html',title='Home',data=paragraph)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0",port=3000)   #   debug 开启调试,更改代码内容,界面相应改变;
                                                    #   host改成0.0.0.0让其他机器可以访问
                                                    #   port=3000端口号

base.html 代码如下:

<html>
    <head>
        {% if title %}
        <title>{{title}}</title>
        {% else %}
        <title>Flask App</title>
        {% endif %}
    </head>
    <body>
        <h3><a href="/">Flask App</a></h3>
        <hr>
        {% block content %}
            <h1>parent template</h1>
        {% endblock %}
    </body>
</html>

index.html 代码如下:

{% extends 'base.html' %}

{% block content %}
    {% for p in data %}
        <p>{{p}}</p>
    {% endfor %}
{% endblock %}

模板的引用

比如,对于导航栏,我们可以把他写在一个组件中。命名为 navbar.html ,例如我们在里面写入:

<h3><a href="/">Flask App</a><a href="/home">Home</a></h3>
<hr>

然后可以再 base.html 中引用,使用如下代码

{% include 'navbar.html' %}

源代码如下:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    paragraph=[
        'section 1',
        'section 2',
        'section 3'
    ]
    return render_template('index.html',title='Home',data=paragraph)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0",port=3000)   #   debug 开启调试,更改代码内容,界面相应改变;
                                                    #   host改成0.0.0.0让其他机器可以访问
                                                    #   port=3000端口号

index.html 代码如下:

{% extends 'base.html' %}

{% block content %}
    {% for p in data %}
        <p>{{p}}</p>
    {% endfor %}
{% endblock %}

base.html 代码如下:

<html>
    <head>
        {% if title %}
        <title>{{title}}</title>
        {% else %}
        <title>Flask App</title>
        {% endif %}
    </head>
    <body>
        {% include 'navbar.html' %}
        {% block content %}
            <h1>parent template</h1>
        {% endblock %}
    </body>
</html>

navbar.html 代码如下:

<h3><a href="/">Flask App</a><a href="/home">Home</a></h3>
<hr>

表单提交

我们已经看到,可以在URL规则中指定http方法。触发函数接收的Form数据可以以字典对象的形式收集它并将其转发到模板以在相应的网页上呈现它。
在以下示例中,'/sign' URL会呈现具有表单的网页(sign.html)。填入的数据会发布到触发 result()函
数的'/result' URL。
result()函数收集字典对象中的request.form中存在的表单数据,并将其发送给result.html。该模板动态呈现表单数据的HTML表格。

下面给出的是应用程序的Python代码:

from flask import Flask,render_template,request

app = Flask(__name__)

# 表单提交页面
@app.route("/sign")
def sign():
    return render_template("sign.html")

# 表单结果显示页面
@app.route("/result",methods=["POST","GET"])    #默认为get,其他请求需要指定
def result():
    if request.method=="POST":
        result=request.form
    return render_template("result.html",result=result)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0",port=3000)

sign.html 代码:

<html>
    <head>
        <title>title</title>  
    </head>
    <body>
        <form action="{{url_for('result')}}" method="POST">    <!-- 使用url_for("函数名") 指定提交的地址-->
            <p>姓名:<input type="text" name="姓名"></p>
            <p>年龄:<input type="text" name="年龄"></p>
          
            <p><input type="submit" value="提交"></p>
        </form>
    </body>
</html>

result.html代码如下:

<html>
    <head>
    </head>
    <body>
  
        <table border="1">
            {% for key,value in result.items()%}
            <tr>
                <td>{{key}}</td>
                <td>{{value}}</td>
            </tr>
            {%endfor%}
        </table>
    </body>
</html>

Echarts入门

官方中文网址:https://echarts.apache.org/zh/index.html
官方实例:https://echarts.apache.org/examples/zh/index.html
官方教程:https://echarts.apache.org/zh/tutorial.html

  • 引入Echarts
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <!-- 引入 ECharts 文件 -->
    <script src="echarts.min.js"></script>
</head>
</html>
  • 设置显示区域
<body>
    <!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
    <div id="main" style="width: 600px;height:400px;"></div>
</body>
  • 初始化Echarts
  • 指定配置项和数据
  • 设置配置项显示图表

完整代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ECharts</title>
    <!-- 引入 echarts.js -->
    <script src="echarts.min.js"></script>
</head>
<body>
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));

        // 指定图表的配置项和数据
        var option = {
            title: {
                text: 'ECharts 入门示例'
            },
            tooltip: {},
            legend: {
                data:['销量']
            },
            xAxis: {
                data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
            },
            yAxis: {},
            series: [{
                name: '销量',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
            }]
        };

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
    </script>
</body>
</html>

WordCloud

WordCloud示例程序

# 引入必要的库
import jieba        #分中文词
import numpy as np  #矩阵运算
import sqlite3      #数据库
from matplotlib import pyplot as plt    #绘图数据可视化
from wordcloud import WordCloud         #词云
from PIL import Image                   #图片处理

# 准备词云所需的词
con=sqlite3.connect("movies.db")
cur=con.cursor()
sql="select instroduction from movies250"
data =cur.execute(sql)
text=""
for item in data:
    text=text+item[0]
    # print(type(item))
  
cur.close()
con.close()

# 分词
cut =jieba.cut(text)
string =' '.join(cut)   # 此处' '双引号中间有空格
print(len(string))  #打印分词数量


img = Image.open(r"./static/assets/img/tree.jpg")   # 打开图片
img_array = np.array(img)   # 将图片转化成数组
wc=WordCloud(
    background_color='white',           # 设置背景颜色
    mask=img_array,                     # 设置背景图片
    font_path='/mnt/c/Windows/Fonts/msyhl.ttc')     #使用WSL子系统需要指定完整的字体路径
                                                    # 若是有中文的话,必须添加中文字体,不然会出现方框,不出现汉字

wc.generate_from_text(string)

# 绘制图片
fig=plt.figure(1)   #新建一个名叫 Figure1的画图窗口
plt.imshow(wc)      #显示图片,同时也显示其格式
plt.axis('off') #是否显示坐标轴

plt.savefig(r"./static/assets/img/word.jpg",dpi=400)    #保存合成图片,dpi是设定分辨率,默认为400

WordCloud配置

WordCloud个参数的含义:

font_path : string #字体路径,需要展现什么字体就把该字体路径+后缀名写上,如:font_path = '黑体.ttf'
width : int (default=400) #输出的画布宽度,默认为400像素
height : int (default=200) #输出的画布高度,默认为200像素
prefer_horizontal : float (default=0.90) #词语水平方向排版出现的频率,默认 0.9 (所以词语垂直方向排版出现频率为 0.1 )
mask : nd-array or None (default=None) #如果参数为空,则使用二维遮罩绘制词云。如果mask 非空,设置的宽高值将被忽略,遮罩形状被 mask 取代。除全白(#FFFFFF)的部分将不会绘制,其余部分会用于绘制词云。如:bg_pic = imread('读取一张图片.png'),背景图片的画布一定要设置为白色(#FFFFFF),然后显示的形状为不是白色的其他颜色。可以用ps工具将自己要显示的形状复制到一个纯白色的画布上再保存,就ok了。
scale : float (default=1) #按照比例进行放大画布,如设置为1.5,则长和宽都是原来画布的1.5倍
min_font_size : int (default=4) #显示的最小的字体大小
font_step : int (default=1) #字体步长,如果步长大于1,会加快运算但是可能导致结果出现较大的误差
max_words : number (default=200) #要显示的词的最大个数
stopwords : set of strings or None #设置需要屏蔽的词,如果为空,则使用内置的STOPWORDS
background_color : color value (default=”black”) #背景颜色,如background_color='white',背景颜色为白色
max_font_size : int or None (default=None) #显示的最大的字体大小
mode : string (default=”RGB”) #当参数为“RGBA”并且background_color不为空时,背景为透明
relative_scaling : float (default=.5) #词频和字体大小的关联性
color_func : callable, default=None #生成新颜色的函数,如果为空,则使用 self.color_func
regexp : string or None (optional) #使用正则表达式分隔输入的文本
collocations : bool, default=True #是否包括两个词的搭配
colormap : string or matplotlib colormap, default=”viridis” #给每个单词随机分配颜色,若指定color_func,则忽略该方法
random_state : int or None #为每个单词返回一个PIL颜色
fit_words(frequencies) #根据词频生成词云
generate(text) #根据文本生成词云
generate_from_frequencies(frequencies[, ...]) #根据词频生成词云
generate_from_text(text) #根据文本生成词云
process_text(text) #将长文本分词并去除屏蔽词(此处指英语,中文分词还是需要自己用别的库先行实现,使用上面的 fit_words(frequencies) )
recolor([random_state, color_func, colormap]) #对现有输出重新着色。重新上色会比重新生成整个词云快很多
to_array() #转化为 numpy array
to_file(filename) #输出到文件

豆瓣Top250项目可视化代码以及资料

Github仓库:https://github.com/imgyh/DouBan_Top250

最后修改:2022 年 12 月 20 日
如果觉得我的文章对你有用,请随意赞赏