Flask框架学习
Flask框架学习
一、Flask框架简介
1.Flask简介
Python中存在众多Web开发框架:Flask、Django、Tornado、Webpy、Web2py、Bottle、Pyramid、Zope2等,现在Python领域最主流的两个Web开发框架是Django和Flask。
轻量级:较其他同类型框架更为灵活、轻便且容易上手,可供小型团队短时间内完成功能丰富的中小型网站或Web服务的实现。
定制性:用户可根据自己的需求添加相应的功能,在保持核心功能简单的同时实现功能的丰富与扩展,其强大的插件库可以实现网站的个性化定制。((比如邮件 Flask Mail,用户认证 Flask Login,数据库Flask SQLAlchemy))
2.Flask特点
2.1 微框架
- Flask旨在保持核心简单易于扩展
- 不会替用户做出太多决策
- 选项(如使用何种模板引擎)通常有多个,用户容易替换
2.2 约定优于配置
设计不好的框架通常需要多个配置文件,每一个文件有许多设置项,程序员需记忆大量的参数配置。
Flask遵循约定优于配置(Convention Over Configuration),也称作按约定编程,是一种软件设计范式。目的在于减少开发人员需要做出决定的数量,从而将开发变的简单,而不失去其中的灵活性,开发人员仅需要规定应用中不符合约定的部分。
3. Django简介
Django 是一个开放源代码的 Web 应用框架,由 Python 写成,它最初是被开发来用于管理一些以新闻内容为主的网站,即是CMS(内容管理系统)软件。
Django 是一个遵循 MVC 设计模式的框架。MVC 是 Model、View、Controller 三个单词的简写,分别代表模型、视图、控制器。Django 也是一个 遵循 MTV 设计模式的框架。MTV 是 Model、Template、View 三个单词的简写,分别代表模型、模版、视图 。
4. Django特点
- 重量型:除了实现Web框架的基本功能外,还内置了大量的模块
5. Flask与Django的比较
主要区别在于:Django功能大而全,Flask只包含基本的功能。
Django(像一个装潢好的房子,提供了各种家具,直接入住就可以):采用一站式解决的思路,Django 集成有模板、表单、路由、认证、基本的数据库管理等内建功能,开发者不用在选择应用的基础设施上花费大量时间。
Flask(像一个毛胚房,需自主选择家具,才可入住): 只提供了最核心的功能,轻巧、简洁,通过定制第三方扩展来实现具体功能。
6. 小结
二、Web开发框架
引入 Web 开发框架的目的:让开发人员只需要专注应用的业务逻辑,非业务逻辑的基础功能则由框架提供,从而提升开发效率。
三、装饰器
- 高阶函数:把函数作为参数或者把函数作为返回值的函数在Python中统称为高阶函数
- 装饰器:本质上就是一个特殊的高阶函数,其参数是一个函数且返回值也是一个函数
装饰器中的装饰的含义是指:对参数函数input的功能进行扩充,得到一个新的函数output
def decorate(input_function) :
def output_function( ):
pass
return output_function
@decorate
def input_function( ) :
pass
首先定义装饰器函数decorate,然后使用@decorate装饰需要增强功能的函数input_function。以上使用装饰器语法@decorate的代码会被翻译如下:
def decorate(input_function):
def output_function( ) :
pass
return output_function
def input_function( ) :
pass
input_function = decorate( input_function)
四、第一个Flask程序
# 导入类flask.Flask
from flask import Flask
# 实例化创建一个Flask应用,app为应用的名称,__name__是一个标识Python模块的名字的变量
# 若当前模块是主模块,那么此模块的名字就是__main__
# 若当前模块是被import的,则此模块名字为文件名
app = Flask(__name__)
# app.route('/')返回一个装饰器,为函数index()绑定对应的URL,当用户访问这个URL时就会触发这个函数
@app.route('/')
def index():
return "Hello World"
# 如果当前模块是主模块,那么此模块的名字就是__main__,此时调用run方法启动Flask应用
if __name__ == '__main__':
app.run()
运行该程序:
访问网址"http://127.0.0.1:5000/"
五、HTTP协议简介
1.概述
HTTP协议是Hyper Text Transfer Protocal(超文本传输协议)的缩写,用于从万维网(World Wide Web)服务器传输超文本到本地浏览器的传送协议。
HTTP协议工作于客服端-服务端架构上。浏览器作为HTTP客户端通过URL向服务端发送请求,服务端根据接收到的请求URL,向客户端发送响应信息。HTTP请求-响应模型如下所示:
2.HTTP请求消息
HTTP协议指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。
浏览器向服务器发出请求时,它向服务器传递了一个请求信息,HTTP请求信息由3部分组成:
- 请求行;
- 请求头;
- 请求空行;
- 请求正文(体)。
Get方式请求(无请求体)示例:
3.常用的HTTP方法
- GET:请求指定的URL页面,这是最常见的方法;
- HEAD:类似于GET,但返回响应中没有具体内容,用于获取报头;
- POST:向指定URL页面提交数据进行处理请求;
- PUT:从客户端向服务器传送数据,取代指定URL的页面
- DELETE:请求服务器删除指定URL的页面
六、URL组成部分详解
1.URL组成
scheme://host:port/path?key=value
- scheme:代表的是访问协议,一般为http或https;
- host:主机名,域名;
- port:端口号。http协议默认端口号80,https默认端口号443,通常情况下使用默认值,无需显示写明端口号;
- path:页面路径
- key=value:查询字符串
2.在Flask中分析URL参数
服务端收到客服端发送的数据后,封装形成一个请求对象,在Flask中,请求对象是一个模块变量flask.request,request对象包含众多属性,与url参数相关的属性如下:
def echo(key, value):
print("%-10s = %s"%(key, value))
@app.route("/query")
def query():
echo("url", request.url)
echo("base_url", request.base_url)
echo("host", request.host)
echo("host_url", request.host_url)
echo("path", request.path)
echo("full_path", request.full_path)
print("-"*30)
print(request.args)
print("userId = %s" % request.args["userId"])
return "hello"
在浏览器中输入 http://localhost/query?userId=123,Flask 程序在终端输出如下:
url = http://127.0.0.1:5000/query?userId=123
base_url = http://127.0.0.1:5000/query
host = 127.0.0.1:5000
host_url = http://127.0.0.1:5000/
path = /query
full_path = /query?userId=123
------------------------------
ImmutableMultiDict([('userId', '123')])
userId = 123
七、Flask中的动态路由
1.动态路由
Flask中的动态路由是指带有参数的页面路径,格式为:/prefix/<参数>
# 动态路由,此处匹配所有以/user/开头的路径
@app.route("/user/<name>")
def show_user(name):
return "My name is %s"%name
2.类型转换器
在 Flask 中,参数类型默认是 string,但是也可以指定其他类型,格式为:/prefix/<类型转换器:参数>
# 类型转换器
@app.route("/age/<int:age>")
def show_age(age):
return "age is %d"%age
Flask中主要有以下4种基本类型转换器:
- string:默认可不写
- int:整数
- float:浮点数
- path:和string类似,但接受斜线
八、Flask的request对象
浏览器访问服务端时。向服务端发送请求。Flask程序使用request对象描述请求信息。
1.简介
浏览器访问服务端,需要将相应的数据发送给服务端,可能有如下场景:
- 通过 URL 参数进行查询,浏览器需要将查询参数发送给服务端
- 提交表单 form 进行查询,浏览器需要将表单 form 中的字段发送给服务端
- 上传文件,浏览器需要将文件发送给服务端
flask.request变量包含的常用属性如下:
属性 | 说明 |
---|---|
method | 当前的请求方法 |
form | 表单参数及其值的字典对象 |
args | 查询字符串的字典对象 |
values | 包含所有数据的字典对象 |
json | 如果 mimetype 是 application/json,这个参数将会解析 json 数据,如果不是则返回 None |
headers | http协议头部 |
cookies | cookie 名称和值的字典对象 |
files | 与上传文件有关的数据 |
url | 请求完整路径 |
示例1---测试form属性:
前端页面:(所在文件名test.html)
后端代码:
# 测试request对象的form属性
@app.route("/addUser", methods=["Get"])
def root():
return render_template("test.html")
@app.route("/addUser", methods=["POST"])
def addUser():
# request.form获取了表单数据,以字典形式返回
name = request.form["name"]
age = request.form["age"]
print(name + "---" + age)
return "addUser ok"
示例二---测试json属性:
前端代码:(所在文件目录:./templates/json.html)
<script>
var data = JSON.stringify({"name":"zhangsan", "age":"20"})
$.ajax({
url: "/addUser2",
type: "post",
contentType: "application/json",
data: data,
success:function (data){
$("#result").html(data)
},
error:function (e){
alert("ERROR")
}
})
</script>
后端代码:
# 测试request对象的json属性
@app.route("/addUser2", methods=["Get"])
def root2():
file = open("./templates/json.html", encoding="utf-8")
return file.read()
@app.route("/addUser2", methods=["POST"])
def addUser2():
json = request.json
print("JSON", json)
print("name = %s"% json["name"])
print("age = %s" % json["age"])
return "addUser2 ok"
九、Flask的jinja2模板
1.简介
浏览器访问网站时,服务端通常会返回一个包含各类信息的html页面。因为网页是动态的,页面中的某些信息需要根据不同的情况来进行调整,比如对登录和未登录用户显示不同的信息,所以页面需要在用户访问时根据程序逻辑动态生成。
把包含变量和运算逻辑的html或者其他格式的文本叫做模板,执行这些变量替换和逻辑计算工作的过程被称为渲染,在Flask中这个工作由模板渲染引擎----jinja2来完成。
2.分界符
jinja2模板文件混合html语法和jinja2语法,使用分界符区分html语法和jinja2语法。有5种常见的分界符:
- {{ 变量 }}
- # 语句
- ## 注释
3. for语句
语法如下:
{% for item in iterable %}
{% endfor %}
示例1:
users = ["tom", "jerry", "mike"]
<ul>
{% for user in users %}
<li>{{ user }}</li>
{% endfor %}
</ul>
示例2:
dict = {"name":"zhangsan", "age":12}
<table border="1px">
{% for key,value in dict.items() %}
<tr>
<td>{{ key }}</td>
<td>{{ value }}</td>
</tr>
{% endfor %}
</table>
4. if语句
语法如下:
{% if cond %}
{% elif cond2 %}
{% else %}
{% endif %}
示例:
a = False
{% if a == True %}
<p>a is True</p>
{% elif a == False %}
<p>a is False</p>
{% else %}
<p>Error</p>
{% endif %}
5. 测试
jinja2提供的tests可以用来在语句里对变量或者表达式进行测试,语法如下:{% variable is test %}
test名称 | 功能 |
---|---|
defined | 变量是否已经定义 |
boolean | 变量的类型是否是 boolean |
integer | 变量的类型是否是 integer |
float | 变量的类型是否是 float |
string | 变量是否是 string |
mapping | 变量的类型是否是字典 |
sequence | 变量的类型是否是序列 |
even | 变量是否是偶数 |
odd | 变量是否是奇数 |
lower | 变量是否是小写 |
upper | 变量是否是大写 |
示例:dict = {"name":"zhangsan", "age":12}
{% if dict is mapping %}
<p>dict是字典</p>
{% endif %}
十、Jinja模板过滤器的使用
1.过滤器简介
1.1 什么是过滤器
通过Jinja2模板中嵌入变量,可以输出变量的值。但是,在很多情况下,还需要修改变量的显示,对变量进行格式化、运算等。为了方便对变量进行处理,jinja2提供了过滤器,过滤器是一个函数,对输入的变量进行变换处理后,返回值作为jinja2模板的输出。
1.2 用法
- {{ var|filter }}
- {{ var|filter(arg) }}
- {{ var|filterA|filterB }}
2.常用的过滤器
2.1 字符串操作
- capitalize(input):把变量input的首字母转成大写,其余字母转成小写。
{{ flAsk|capitalize }}--->Flask
- title(input):把变量 input 中的每个单词的首字母都转成大写。
{{ "hello world"|title }}--->Hello World
- lower(input):把字符串 input 转成小写。
{{ "ABc"|lower }}--->abc
- upper(input):把字符串 input 转成大写。
{{ "abc"|upper }}--->ABC
- revsere(input):把字符串 input 反转。
{{ "abc"|reverse }}--->cba
- format(string, arg1, arg2, …):对字符串 string 进行格式化。
{{ "I am %s, I am %d years old"|format("zhangsan",13) }}--->I am zhangsan, I am 13 years old
2.2 列表操作
- first(list):获取列表 list 中的第一个元素。
{{ ["tom", "jerry", "amy"]|first }}--->tom
- last(list):获取列表 list 中的最后一个元素。
{{ ["tom", "jerry", "amy"]|first }}--->amy
- length(list):获取列表 list 长度。
{{ ["tom", "jerry", "amy"]|length }}--->3
- sum(list):对列表 list 求和。
{{ [1, 2, 3]|sum }}--->6
- sort(list, reverse = False):对列表 list 排序,参数 reverse 为真表示对 list 按倒序进行排序。
{{ [1, 2, 3]|sort(reverse=True) }}---> [3, 2, 1]
- join(list, seperator):将序列 list 中包含的字符串拼接成一个字符串,使用 seperator 作为连接符。
{{ ["tom", "jerry", "amy"]|join(",") }}--->tom,jerry,amy
2.3 其他常用过滤器
- default(value, default_value=’’):如果变量 value 不存在,使用默认值 default_value。
{{ name|default("lili") }}--->lili
- striptags(input):把变量 input 中所有的 HTML 标签都删掉。
{{ "<h1>hello world</h1>"|striptags }}--->hello world
2.4 自定义过滤器
- 使用 app.add_template_filter(filter_function, filter_name),将函数 filter_function 注册为名称为 filter_name 的过滤器;
- 使用 @app.template_filter(filter_name) 装饰一个函数 filter_function,将函数 filter_function 注册为名称为 filter_name 的过滤器。
示例如下(数值减1过滤器):
@app.template_filter("myFilter")
def myFilter(input):
output = input-1
return output
十一、Flask标准类试图
1.设置路由方式
before: 将URL路径和一个视图函数关联
now:将URL路径和一个视图类关联
2.视图类基本用法
2.1 基本用法
Flask.views.View是Flask的标准视图类,用户定义的视图类需要继承Flask.views.View。使用视图类的步骤如下:
- 用户定义一个视图类,继承于flask.views.View;
- 在视图类中定义方法dispatch_request,处理请求,返回HTML文本给客户端;
- 使用app.add_url_rule(rule, view_func)将URL路径和视图类绑定。
视图类示例如下:
# 视图类
class Index(views.View):
def dispatch_request(self):
return "hello world"
app.add_url_rule(rule="/views", view_func=Index.as_view("Index"))
2.2 as_view函数的功能
视图类的本质是视图函数,函数View.as_view()返回一个视图函数,为理解透彻as_view函数的功能,我们实现一个简化版本的as_view函数,代码如下:
# 视图类
class Index(views.View):
def dispatch_request(self):
return "hello world"
@staticmethod
def as_view(name):
index = Index()
return index.dispatch_request
# 将路径为 /views 的 URL 和视图类 Index 绑定
app.add_url_rule(rule="/views", view_func=Index.as_view("Index"))
as_view方法它首先创建了一个Index类的实例index,然后返回方法dispatch_request,当页面访问路径/views时,最终会调用dispatch_request方法。
十二、Flask蓝图
Flask 中使用蓝图,避免所有代码放在单个程序文件中。
1.蓝图简介
蓝图 (Blueprint) 是 Flask 程序的模块化处理机制,它是一个存储视图方法的集合,Flask 程序通过 Blueprint 来组织 URL 以及处理请求。
Flask的Blueprint具有如下特点:
- 一个项目可以具有多个Blueprint
- Blueprint可以单独具有自己的模板、静态文件的目录
- 在应用初始化时,注册需要使用的Blueprint
2.基本用法
2.1 假设网站中包含如下4个页面:
URL | 视图函数 |
---|---|
/news/society | society_news |
/news/tech | tech_news |
/products/car | car_products |
/products/baby | baby_product |
2.2 划分蓝图
2.3 程序实现
创建news模块:
from flask import Blueprint
# 定义蓝图对象news
# 第一个参数:蓝图的名称
# 第二个参数:该蓝图所在的模块名称
# 第三个参数:指定页面的URL前缀
blueprint = Blueprint("news", __name__, url_prefix="/news")
# 将路径和函数相关联
@blueprint.route("/society")
def society_news():
return "社会新闻板块"
@blueprint.route("/tech")
def tech_news():
return "IT 新闻板块"
创建products模块:
from flask import Blueprint
# 定义蓝图对象products
# 第一个参数:蓝图的名称
# 第二个参数:该蓝图所在的模块名称
# 第三个参数:指定页面的URL前缀
blueprint = Blueprint("products", __name__, url_prefix="/products")
# 将路径和函数相关联
@blueprint.route("/car")
def car_products():
return "汽车产品板块"
@blueprint.route("/baby")
def baby_products():
return "婴儿产品板块"
编写主程序app:
from flask import Flask
# 导入模块,测试蓝图
import news
import products
app = Flask(__name__)
# 在应用中注册蓝图对象
app.register_blueprint(news.blueprint)
app.register_blueprint(products.blueprint)
app.run()
结果测试:
3.更具扩展性的架构
根据Flask程序的扩展性分为如下三种类型:
- 所有的页面逻辑放在同一个文件中:不具备扩展性
- 使用一个独立的python文件实现蓝图(点2"基本用法"中便是此种架构):具备一定的扩展性
- 使用一个独立的目录实现蓝图:扩展性最好
对上述例子进行架构更改,使之扩展性达到最好,架构如下图所示:
实现步骤:
实现news/init.py:
from flask import Blueprint, render_template
# 定义蓝图对象news
# 第一个参数:蓝图的名称
# 第二个参数:该蓝图所在的模块名称
# 第三个参数:指定页面的URL前缀
# 第四个参数指定当前蓝图的私有模板文件夹,必须指定
# 第五个参数指定当前蓝图的私有静态文件夹,必须指定
blueprint = Blueprint("news", __name__, url_prefix="/news", template_folder="templates", static_folder="static")
# 将路径和函数相关联
@blueprint.route("/society")
def society_news():
return render_template("society.html", data="社会新闻板块")
@blueprint.route("/tech")
def tech_news():
return "IT 新闻板块"
实现news/static/news.css:
h1{
color: red;
}
实现news/templates/society.html:
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="static/css/news.css" rel="stylesheet">
</head>
<body>
<h1>{{ data }}</h1>
</body>
实现app.py:
# 导入蓝图包,测试蓝图
import news
import products
# 在应用中注册蓝图对象
app.register_blueprint(news.blueprint)
app.register_blueprint(products.blueprint)
app.run()
测试"localhost:5000/news/society"网址:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通