Flask 框架引入

Flask

安装Flask

shell 复制代码
pip3 install flask	

创建Flask项目

在文件夹下创建app.py,在其中写入以下内容

py 复制代码
from flask import Flask

app = Flask(__name__)  # 实例化app对象

@app.route('/',methods=['GET','POST'])  # 路由装饰器,将路由映射到函数,methods是请求方法
def hello_world():
    return 'hello world'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=54188, debug=True)   # 调用run()方法启动服务器,启用debug可以实时显示代码更改后的情况

当同一个路由装饰器装饰多个视图函数时,只会访问第一个路由下的视图函数的返回值,即先到先得

当同一个视图函数被多个路由装饰器装饰时,所有的路由都会正常执行当前视图函数

更改模板\静态资源文件夹等

py 复制代码
app = Flask(__name__,static_folder="static",template_folder='templates',...)

修改配置文件

方法零 在启动项目时添加参数
shell 复制代码
python -m flask run -h 0.0.0.0 -p 54188 --debug 
方法一 在app.py中直接修改
py 复制代码
# app.py
app.config['DEBUG'] = True
# print(app.config)	# 打印可配置的项目
# print(app.config.get('DEBUG')) # 打印指定配置的内容
# print(dir(app.config)) # 打印可以调用的方法

Flask框架的配置文件是一个字典形式,直接通过Key定位到待修改的项目,然后进行修改

方法二 添加一个setting.py文件统一管理
py 复制代码
# app.py
app.config.from_pyfile('setting.py')

# setting.py
DEBUG = True
方法三 通过对象修改
py 复制代码
# 创建一个类,然后在类中添加配置项
class Spt2503(object):
    DEBUG = True
    
class Spt2504(Spt2503):
    HOST = '0.0.0.0'

# 调用命令获取对象的属性,通过其修改配置
app.config.from_object(Spt2504)

查看已有的路由信息

py 复制代码
print(app.url_map)  # 打印当前路由列表
print(dir(app.url_map))  # 打印路由中可配置的项目
print(dir(app.url_map.iter_rules))

待整理...

根据已有的函数动态填充指定url

app.url_for(endpoint, \**values)

  • endpoint:路由关联的端点名(通常是视图函数名)
  • **values:URL 变量部分的参数(如 /user/<username> 中的 username

根据端点名称(endpoint)和参数动态生成 URL

py 复制代码
url = app.url_for('user_profile', username='alice')

返回JSON格式信息

py 复制代码
@app.route('/')
def ok():
    return jsonify({"code":200, "message":"hello"})

通过动态路由实现在链接传值

直接在访问链接的后面添加要传的值

py 复制代码
@app.route('/get/<string:name>')  # 在路由中命名
    # 一般常用的类型有 int float string 三种类型
def get(name):
    print()
    return f'hello{name}'

异常处理

py 复制代码
@app.errorhandler(404)
def pageNotFound(e):
    return f'页面未找到<hr>{e}'

Flask 请求和响应数据

py 复制代码
from flask import Flask
    from flask import request
    from flask import render_template
    from flask import redirect
    from flask import make_response
    app = Flask(__name__)
    @app.route('/login.html', methods=['GET', "POST"])
    def login():
        # 请求相关信息
        # request.method
        # request.args
        # request.form
        # request.values
        # request.cookies
        # request.headers
        # request.path
        # request.full_path
        # request.script_root
        # request.url
        # request.base_url
        # request.url_root
        # request.host_url
        # request.host
        # request.files
        # obj = request.files['the_file_name']
        # obj.save('/var/www/uploads/' + secure_filename(f.filename))
    
        # 响应相关信息
        # return "字符串"
        # return render_template('html模板路径',**{})
		# return redirect('/index.html')
		# response = make_response(render_template('index.html'))
		# response是flask.wrappers.Response类型
		# response.delete_cookie('key')
 		# response.set_cookie('key', 'value')
 		# response.headers['X-Something'] = 'A value'
 		# return response
 		return "内容"
 	if __name__ == '__main__':
 		app.run()

获取前端表单内容

在 Flask 中获取前端表单内容主要有以下两种方式(根据表单的 Content-Type 选择):


  1. application/x-www-form-urlencoded(默认表单类型)

前端示例(HTML):

html 复制代码
<form action="/submit" method="POST">
  <input type="text" name="username">
  <input type="password" name="password">
  <button type="submit">提交</button>
</form>

后端处理(Flask):

python 复制代码
from flask import request

@app.route('/submit', methods=['POST'])
def handle_form():
    username = request.form.get('username')  # 推荐使用 .get() 避免 KeyError
    password = request.form.get('password')
    return f"Received: {username}, {password}"

  1. application/json(AJAX/前端框架常用)

前端示例(JavaScript):

javascript 复制代码
// 使用 Fetch API 发送 JSON
fetch('/submit', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ username: 'test', password: '123' })
})

后端处理(Flask):

python 复制代码
from flask import request, jsonify

@app.route('/submit', methods=['POST'])
def handle_json():
    data = request.get_json()  # 自动解析 JSON
    username = data.get('username')
    password = data.get('password')
    return jsonify({"status": "success", "data": data})

获取前端上传的文件

在 Flask 中处理文件上传需要结合 enctype="multipart/form-data" 表单和 request.files 对象。以下是具体实现方法:


  1. 前端表单(HTML)
html 复制代码
<form action="/upload" method="POST" enctype="multipart/form-data">
  <input type="file" name="file">
  <button type="submit">上传</button>
</form>

  1. 后端处理(Flask)
python 复制代码
from flask import request, jsonify
import os

UPLOAD_FOLDER = 'uploads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)  # 确保上传目录存在

@app.route('/upload', methods=['POST'])
def handle_upload():
    if 'file' not in request.files:
        return jsonify({"error": "No file part"}), 400
    
    file = request.files['file']
    if file.filename == '':
        return jsonify({"error": "No selected file"}), 400

    if file:
        file.save(os.path.join(UPLOAD_FOLDER, file.filename))
        return jsonify({"status": "success", "filename": file.filename})

返回信息修改和Cookie\Session设置

可以返回一个元组,这样的元组必须是 (response, status, headers) 的 形式,且至少包含一个元素。 status 值会覆盖状态代码, headers 可以是 一个列表或字典,作为额外的消息标头值

py 复制代码
@app.route('/set_res1')
def res1():
    print('元组返回,外面的括号可以省略')
    return 'hello world', 200, {'Content-Type':'text/html;chatset=utf-8'}

也可以通过make_response()来设置返回的信息,包括设置cookie和session

py 复制代码
@app.route('/set_res')
def setRes():
    res = make_response('hello')
    res.status_code = 200
    res.header['Content-Type'] = 'text/html;chatset=gbk'
    return res

@app.route('/set_cookie')
def setCookie():
    res = make_response('hello world')
    res.set_cookie('key','value',max_age=3600*24*15) # Cookie一般设置半个月,要删除Cookie,就将事件设置为0
    return res

@app.route('/get_cookie')
def getCookie():
    print(request.cookies)  # 获取全部Cookie
    print(request.cookies.get('key'))	# 获取指定key的Cookie
    return 'hello world'

@app.route('/set_session')
def setSession():
    session['key'] = 'value'
    return '设置成功'

@app.route('/get_session')
def getSession():
    ses = session.get('key')
    return ses

@app.route('/del_session')
def delSession():
    ses = session.pop('key')
    return 'Session删除成功'

session还有许多方法,类似clear(),update()等用法

要设置session,必须设置一个密钥来保护安全,例如在代码中输入app.config['SECRET_KEY'] = 'SECRET_KEY'来设置密钥

设置类视图

py 复制代码
...
from flask.views import MethodView
...
class cbv(MethodView):
    def get(self):	# 固定写法,实现GET方法
        return 'hello'

user_view = cbv.as_view('cbv') # cbv是传值的名字(类似前端表单的name),一般等同于类名
app.add_url_rule('/rule',view_func=user_view,methods=['GET','POST'])  # 添加路由

请求\应用上下文(线程局部变量)

请求上下文(request context) request和session

应用上下文(application context) current_app和g

current_app 表示当前运行程序文件的程序实例;g 表示临时存储的对象,每次请求都会重设这个变量,请求完后会清空

请求钩子函数(中间件)

请求钩子是通过装饰器的形式实现,Flask支持如下四种请求钩子:

  • before_first_request:在处理第一个请求前运行。
  • before_request:在每次请求前运行。
  • after_request:如果没有未处理的异常抛出,在每次请求后运行。
  • teardown_request:在每次请求后运行,即使有未处理的异常抛出。
  1. before_first_request

作用:在应用处理第一个客户端请求之前运行,通常用于初始化操作(如数据库连接、全局配置等)。

python 复制代码
from flask import Flask
app = Flask(__name__)

@app.before_first_request
def initialize():
    print("This runs ONCE before the first request.")

@app.route('/')
def home():
    return "Home Page"

if __name__ == '__main__':
    app.run()

行为 :启动应用后,首次访问 / 时会打印 "This runs ONCE before the first request.",后续请求不再触发。


  1. before_request

作用 :在 每个请求 处理前运行,常用于身份验证、请求预处理等。

python 复制代码
from flask import Flask, request
app = Flask(__name__)

@app.before_request
def log_request_info():
    print(f"Request Path: {request.path}")

@app.route('/')
def home():
    return "Home Page"

@app.route('/api')
def api():
    return "API Data"

行为 :每次访问 //api 时,均会打印当前请求路径(如 "Request Path: /api")。


  1. after_request

作用 :在每次请求 正常完成后(无未处理异常)运行,常用于修改响应(如添加头信息)。

python 复制代码
from flask import Flask, make_response
app = Flask(__name__)

@app.after_request
def add_header(response):
    response.headers['X-Custom-Header'] = 'Hello'
    print("Response modified")
    return response

@app.route('/')
def home():
    return "Home Page"

行为 :访问 / 后,响应会添加 X-Custom-Header,并打印 "Response modified"。若视图函数抛出异常,此钩子不执行。


  1. teardown_request

作用 :在每次请求 结束后 运行(即使有未处理异常),适用于清理资源(如关闭文件、数据库连接)。

python 复制代码
from flask import Flask
app = Flask(__name__)

@app.teardown_request
def cleanup(exception):
    if exception:
        print(f"An error occurred: {exception}")
    print("Resource cleanup completed")

@app.route('/error')
def force_error():
    raise ValueError("Demo Error")

@app.route('/')
def home():
    return "Home Page"

行为

  • 访问 /:打印 "Resource cleanup completed"
  • 访问 /error:先打印错误信息,再打印 "Resource cleanup completed"
钩子类型 触发时机 异常影响
before_first_request 首次请求前
before_request 每次请求前 后续流程终止
after_request 请求正常完成后 未处理异常时跳过
teardown_request 请求结束后(无论是否有异常) 始终执行

Jinja2 模板语法

  1. Flask 应用代码 (app.py)
python 复制代码
from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def home():
    # 传递变量到模板
    user = {"name": "Alice", "age": 25}
    numbers = [1, 2, 3, 4]
    return render_template(
        'index.html',  # 模板文件名
        user=user,     # 变量1:字典
        numbers=numbers,  # 变量2:列表
        greeting="Hello World!"  # 变量3:字符串
    )

if __name__ == '__main__':
    app.run()

  1. 模板文件 (templates/index.html)
html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>Jinja2 Demo</title>
</head>
<body>
    <h1>{{ greeting }}</h1>  <!-- 输出字符串变量 -->
    
    <!-- 输出字典内容 -->
    <p>User: {{ user.name }}, Age: {{ user.age }}</p>
    
    <!-- 循环输出列表 -->
    <ul>
    {% for num in numbers %}
        <li>Number: {{ num }}</li>
    {% endfor %}
    </ul>

    <!-- 条件判断 -->
    {% if user.age > 18 %}
        <p>This user is an adult.</p>
    {% endif %}
</body>
</html>

Web表单

WTForms支持的HTML标准字段

|

|

| ------------------------------------------------------------ | ------------------------------------------------------------ |

WTForms常用验证函数

应用: 判断密码输入是否一致

python 复制代码
# 定义自己的表单类
class MyForm(FlaskForm):
    username = StringField('用户名')
    password = PasswordField('密码')
    qrpassword = PasswordField('确认密码', validators=[EqualTo('password', message='密码不一致')])

@app.route('/form', methods=['GET', 'POST'])
def form():
    form = MyForm(request.form if request.method == 'POST' else None)

    if request.method == 'POST':
        if form.validate():
            print(form.username.data)
            pd = form.password.data
            rpd = form.qrpassword.data
            print(pd, rpd)
            # 成功处理后的逻辑
        else:
            print("表单验证失败:", form.errors)

    # 无论 GET 还是 POST,都传递表单对象到模板
    return render_template('main.html', form=form)
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
        表单 测试
    </title>
</head>
<body>
<form action="/form" method="post">
    {{ form.csrf_token }}
    <input type="text" name="username" id="" value="{{}}">
    <input type="password" name="password" id="">
    <input type="password" name="qrpassword" id="">
    <input type="submit" value="提交">
</form>
</body>
</html>

控制语句

常用的几种控制语句: 模板中的if控制语句

html 复制代码
{% if %} {% endif %} 

模板中的for语句

html 复制代码
{% for item in samples %} {% endfor %}

类似于python中的函数,宏的作用就是在模板中重复利用代码,避免代码 冗余。 Jinja2支持宏,还可以导入宏,需要在多处重复使用的模板代码片段可以写 入单独的文件,再包含在所有模板中,以避免重复。

定义宏

html 复制代码
{% macro input() %}
<input type="text"
       name="username"
       value=""
       size="30"/>
{% endmacro %}

调用宏

html 复制代码
{{ input() }}

定义带参数的宏

html 复制代码
{% macro input(name,value='',type='text',size=20) %}
<input type="{{ type }}"
       name="{{ name }}"
       value="{{ value }}"
       size="{{ size }}"/>
{% endmacro %}

调用宏,并传递参数

html 复制代码
{{ input(value='name',type='password',size=40)}}

把宏单独抽取出来,封装成html文件,其它模板中导入使用

文件名可以自定义macro.html

html 复制代码
{% macro function() %}
<input type="text" name="username" placeholde="Username">
<input type="password" name="password" placeholde="Password">
<input type="submit">
{% endmacro %}

在其它模板文件中先导入,再调用

html 复制代码
{% import 'macro.html' as func %}
{{ func.function() }}

模板继承

模板继承是为了重用模板中的公共内容。一般Web开发中,继承主要使用在网站的顶部菜单、底部。这些内容可以定义在父模板中,子模板直接继承,而不需要重复书写。

{% block top %}``{% endblock %}标签定义的内容,相当于在父模板中挖个坑,当子模板继承父模板时,可以进行填充。

子模板使用extends指令声明这个模板继承自哪?父模板中定义的块在子模板中被重新定义,在子模板中调用父模板的内容可以使用super()。

父模板

html 复制代码
{% block top %}
顶部
{% endblock top %}

{% block content %}
中间
{% endblock content %}

{% block bottom %}
底部
{% endblock bottom %}

子模板

html 复制代码
{% extends 'base.html' %}
{% block content %}
需要填充的内容
{% endblock content %}

模板继承使用时注意点:

  • 不支持多继承。
  • 为了便于阅读,在子模板中使用extends时,尽量写在模板的第一行。
  • 不能在一个模板文件中定义多个相同名字的block标签。
  • 当在页面中使用多个block标签时,建议给结束标签起个名字,当多个block嵌套时,阅读性更好。

包含

Jinja2模板中,除了宏和继承,还支持一种代码重用的功能,叫包含 (Include)。它的功能是将另一个模板整个加载到当前模板中,并直接渲染。

html 复制代码
 {% include 'hello.html' ignore missing %}

包含在使用时,如果包含的模板文件不存在时,程序会抛出 TemplateNotFound异常,可以加上ignore missing关键字。如果包含的 模板文件不存在,会忽略这条include语句。

三者之间的比较

宏(Macro)、继承(Block)、包含(include)均能实现代码的复用。

  • 继承(Block)的本质是代码替换,一般用来实现多个页面中重复不变的区域。

  • 宏(Macro)的功能类似函数,可以传入参数,需要定义、调用。

  • 包含(include)是直接将目标模板文件整个渲染出来。

数据库

导包

shell 复制代码
pip3 install flask-sqlalchemy
pip3 install flask-mysqldb

设置数据库

py 复制代码
#连接操作
app.config['SQLALCHEMY_DATABASE_URI'] = 
'mysql://root:mysql@127.0.0.1:3306/zb'
#设置每次请求结束后会自动提交数据库中的改动
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
#保证数据库数据和模型类数据一致
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)

常用的SQLAlchemy字段类型

常用的SQLAlchemy选项

常用的SQLAlchemy列选项 常用的SQLAlchemy关系选项

基本操作

常用的SQLAlchemy查询操作
常用的SQLAlchemy查询过滤器 常用的SQLAlchemy查询执行器
创建表
py 复制代码
db.create_all()
删除表
py 复制代码
db.drop_all()
插入一条数据
py 复制代码
ro1 = Role(name='admin')
db.session.add(ro1)
db.session.commit()
#再次插入一条数据
ro2 = Role(name='user')
db.session.add(ro2)
db.session.commit()
插入多条数据
py 复制代码
us1 = User(name='wang',email='wang@163.com',pswd='123456',role_id=ro1.id)
us2 = User(name='zhang',email='zhang@189.com',pswd='201512',role_id=ro2.id)
us3 = User(name='chen',email='chen@126.com',pswd='987654',role_id=ro2.id)
us4 = User(name='zhou',email='zhou@163.com',pswd='456789',role_id=ro1.id)
db.session.add_all([us1,us2,us3,us4])
db.session.commit()
查询

filter_by()精确查询

返回名字等于wang的所有人

py 复制代码
User.query.filter_by(name='wang').all()

first()返回查询到的第一个对象

py 复制代码
User.query.first()

all()返回查询到的所有对象

py 复制代码
User.query.all()

filter()模糊查询,返回名字结尾字符为g的所有数据。

py 复制代码
User.query.filter(User.name.endswith('g')).all()

get(),参数为主键,如果主键不存在没有返回内容

py 复制代码
User.query.get()

逻辑非,返回名字不等于wang的所有数据

py 复制代码
User.query.filter(User.name!='wang').all()

逻辑与,需要导入and ,返回 and()条件满足的所有数据

py 复制代码
from sqlalchemy import and_
User.query.filter(and_(User.name!='wang',User.email.endswith('163.com'))).all()

逻辑或,需要导入or_

py 复制代码
from sqlalchemy import or_
User.query.filter(or_(User.name!='wang',User.email.endswith('163.com'))).all()

not_ 相当于取反

py 复制代码
from sqlalchemy import not_
User.query.filter(not_(User.name=='chen')).all()

查询数据后删除

py 复制代码
user = User.query.first()
db.session.delete(user)
db.session.commit()
User.query.all()

更新数据

py 复制代码
user = User.query.first()
user.name = 'dong'
db.session.commit()
User.query.first()

使用update更新

py 复制代码
User.query.filter_by(name='zhang').update({'name':'li'})
db.session.commit()

应用:查询角色

角色和用户的关系是一对多的关系,一个角色可以有多个用户,一个用户只能属于一个角色

查询角色的所有用户

py 复制代码
#查询roles表id为1的角色
ro1 = Role.query.get(1)
#查询该角色的所有用户
ro1.us

查询用户所属角色

py 复制代码
#查询users表id为3的用户
us1 = User.query.get(3)
#查询用户属于什么角色
us1.role

创建迁移仓库

py 复制代码
# 这个命令会创建migrations文件夹,所有迁移文件都放在里面。
python database.py db init
创建迁移脚本

自动创建迁移脚本有两个函数,upgrade()函数把迁移中的改动应用到数据库中,downgrade()函数则将改动删除。自动创建的迁移脚本会根据模型定义和数据库当前状态的差异,生成upgrade()downgrade()函数的内容。对比不一定完全正确,有可能会遗漏一些细节,需要进行检查。

bash 复制代码
# 创建自动迁移脚本
python database.py db migrate -m 'initial migration'
更新数据库
bash 复制代码
python database.py db upgrade
回退数据库

回退数据库时,需要指定回退版本号,由于版本号是随机字符串,为避免出错,建议先使用python database.py db history命令查看历史版本的具体版本号,然后复制具体版本号执行回退。

bash 复制代码
python database.py db downgrade 版本号
相关推荐
小王不爱笑1322 小时前
Java基础知识(十四)
java·windows·python
烟锁池塘柳02 小时前
【已解决,亲测有效】解决使用Python Matplotlib库绘制图表中出现中文乱码(中文显示为框)的问题的方法
开发语言·python·matplotlib
周小码2 小时前
llama-stack实战:Python构建Llama应用的可组合开发框架(8k星)
开发语言·python·llama
pianmian12 小时前
Spring 项目骨架
java·后端·spring
IT学长编程2 小时前
计算机毕业设计 基于Hadoop的南昌房价数据分析系统的设计与实现 Python 大数据毕业设计 Hadoop毕业设计选题【附源码+文档报告+安装调试
大数据·hadoop·python·毕业设计·课程设计·毕业论文·豆瓣电影数据可视化分析
郑洁文3 小时前
豆瓣网影视数据分析与应用
大数据·python·数据挖掘·数据分析
kyle~3 小时前
python---PyInstaller(将Python脚本打包为可执行文件)
开发语言·前端·python·qt
小程序设计3 小时前
【springboot+vue】高校迎新平台管理系统(源码+文档+调试+基础修改+答疑)
vue.js·spring boot·后端
guidovans3 小时前
Crawl4AI精准提取结构化数据
人工智能·python·tensorflow