Flask入门练习:
Flask练习
包含的功能
- 基础路由 :简单的 URL 与函数映射
- 动态路由 :在 URL 中使用变量(字符串、整数等类型)
- 自定义 URL 转换器 :实现了手机号码格式的参数验证
- 请求参数处理 :
- 获取查询参数(GET 请求)
- 处理表单数据(POST 请求)
- 文件上传功能
- 响应处理 :
- 返回 HTML 内容
- 返回 JSON 数据
- 自定义响应(状态码、响应头和 Cookie)
- 重定向 :URL 重定向示例
1.app.py :主应用程序文件,包含所有路由和功能实现
# 导入必要的模块
# Flask: Web框架的核心类,用于创建应用实例
# request: 用于获取HTTP请求数据(表单数据、查询参数、文件等)
# jsonify: 将Python字典转换为JSON响应
# redirect: 用于重定向请求到其他URL
# url_for: 用于构建URL,接受视图函数名称作为参数
# make_response: 用于创建自定义响应对象
from flask import Flask, request, jsonify, redirect, url_for, render_template, make_response
# os: 提供与操作系统交互的功能,用于文件路径操作和目录创建
import os
# secure_filename: 用于安全地处理上传的文件名,防止路径遍历攻击
from werkzeug.utils import secure_filename
# BaseConverter: 用于创建自定义URL转换器的基类
from werkzeug.routing import BaseConverter
# 创建Flask应用实例
# __name__: 当前模块的名称,Flask用它来确定应用的根路径
app = Flask(__name__)
# 配置参数设置
# app.config.update(): 一次性更新多个配置项
app.config.update(
# DEBUG: 开启调试模式,启用自动重载和详细错误页面
# True: 开启调试模式,False: 关闭调试模式
DEBUG=True,
# SECRET_KEY: 用于会话安全的密钥,应当保密且复杂
# 在生产环境中应使用随机生成的复杂字符串
SECRET_KEY='your_secret_key_here',
# UPLOAD_FOLDER: 文件上传的存储路径
# os.path.dirname(os.path.abspath(__file__)): 获取当前脚本所在的目录
# os.path.join(): 连接路径组件,确保跨平台兼容性
UPLOAD_FOLDER=os.path.join(os.path.dirname(os.path.abspath(__file__)), 'uploads'),
# ALLOWED_EXTENSIONS: 允许上传的文件类型集合
# 这里允许上传文本文件、PDF文件和常见图片格式
ALLOWED_EXTENSIONS={'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
)
# 确保上传文件夹存在
# os.makedirs(): 创建目录,如果目录已存在则不报错
# exist_ok=True: 如果目录已存在,不会引发异常
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
# 自定义转换器 - 手机号码转换器
# 继承BaseConverter类来创建自定义URL转换器
class MobileConverter(BaseConverter):
"""自定义手机号码URL转换器
用于验证URL中的参数是否符合中国大陆手机号格式
例如: /mobile/13812345678
"""
# 定义正则表达式模式
# r'1[3-9]\d{9}': 匹配中国大陆手机号码格式
# 1开头,第二位是3-9之间的数字,后面跟9个数字
regex = r'1[3-9]\d{9}'
def to_python(self, value):
"""将URL中的参数转换为Python对象
参数:
value (str): URL中捕获的字符串值
返回:
str: 处理后的值,这里直接返回原值
"""
return value
def to_url(self, value):
"""将Python对象转换为URL中的参数
参数:
value (str): 要转换为URL参数的Python对象
返回:
str: URL中使用的字符串,这里直接返回原值
"""
return value
# 注册自定义转换器
# app.url_map.converters: 存储所有URL转换器的字典
# 'mobile': 转换器的名称,在路由中使用,如 <mobile:phone_number>
app.url_map.converters['mobile'] = MobileConverter
# 辅助函数 - 检查文件扩展名是否允许
def allowed_file(filename):
"""检查上传的文件扩展名是否在允许列表中
参数:
filename (str): 要检查的文件名
返回:
bool: 如果文件扩展名在允许列表中返回True,否则返回False
"""
# '.' in filename: 检查文件名中是否包含点号(即是否有扩展名)
# filename.rsplit('.', 1)[1].lower(): 获取文件扩展名并转为小写
# rsplit('.', 1): 从右侧按点号分割,最多分割1次,返回列表
# [1]: 获取分割后的第二部分,即扩展名
# lower(): 将扩展名转换为小写,以便不区分大小写比较
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']
# 路由:首页
# @app.route(): 路由装饰器,将URL规则映射到视图函数
# '/': URL规则,这里是根路径
@app.route('/')
def index():
"""首页路由 - 返回HTML内容
返回:
str: 包含链接列表的HTML内容,展示应用的所有功能示例
"""
# 返回一个HTML字符串,包含应用功能的链接列表
return '''
<h1>Flask学习示例</h1>
<p>这是一个包含Flask基础功能的示例应用</p>
<ul>
<li><a href="/hello">基本路由示例</a></li>
<li><a href="/user/admin">动态路由示例 - 字符串参数</a></li>
<li><a href="/user/123">动态路由示例 - 整数参数</a></li>
<li><a href="/mobile/13812345678">自定义转换器示例 - 手机号</a></li>
<li><a href="/query?name=flask&age=10">查询参数示例</a></li>
<li><a href="/form">表单提交示例</a></li>
<li><a href="/upload">文件上传示例</a></li>
<li><a href="/json">JSON响应示例</a></li>
<li><a href="/redirect-example">重定向示例</a></li>
<li><a href="/custom-response">自定义响应示例</a></li>
</ul>
'''
# 路由:基本示例
@app.route('/hello')
def hello():
"""基本路由示例 - 返回简单字符串
返回:
str: 简单的问候字符串
"""
# 返回一个简单的字符串作为HTTP响应
return 'Hello, Flask!'
# 路由:动态路由 - 字符串参数
# <string:username>: 动态URL部分,捕获字符串类型的参数并命名为username
@app.route('/user/<string:username>')
def show_user_profile(username):
"""动态路由示例 - 接收字符串参数
参数:
username (str): 从URL中捕获的用户名字符串
返回:
str: 包含用户名的响应字符串
"""
# f-string格式化字符串,将捕获的参数插入到响应中
return f'用户名: {username}'
# 路由:动态路由 - 整数参数
# <int:user_id>: 动态URL部分,捕获整数类型的参数并命名为user_id
# 如果参数不是整数,Flask会返回404错误
@app.route('/user/<int:user_id>')
def show_user_id(user_id):
"""动态路由示例 - 接收整数参数
参数:
user_id (int): 从URL中捕获的用户ID整数
返回:
str: 包含用户ID的响应字符串
"""
# 返回包含整数参数的字符串
return f'用户ID: {user_id}'
# 路由:自定义转换器 - 手机号
# <mobile:phone_number>: 使用自定义的mobile转换器处理URL参数
@app.route('/mobile/<mobile:phone_number>')
def show_mobile(phone_number):
"""自定义转换器示例 - 接收符合手机号格式的参数
参数:
phone_number (str): 从URL中捕获的手机号码字符串
必须符合中国大陆手机号格式
返回:
str: 包含手机号的响应字符串
"""
# 返回包含手机号的字符串
return f'手机号: {phone_number}'
# 路由:获取查询参数
@app.route('/query')
def query_params():
"""查询参数示例 - 获取URL中的查询参数
URL示例: /query?name=flask&age=10
返回:
str: 包含查询参数值的响应字符串
"""
# request.args: 包含所有查询参数的不可变字典(ImmutableMultiDict)
# get('name', '未提供'): 获取名为'name'的参数值,如果不存在则返回默认值'未提供'
name = request.args.get('name', '未提供')
age = request.args.get('age', '未提供')
# 返回包含查询参数的字符串
return f'查询参数 - 姓名: {name}, 年龄: {age}'
# 路由:表单提交
# methods=['GET', 'POST']: 指定路由支持的HTTP方法
# 默认情况下,路由只响应GET请求
@app.route('/form', methods=['GET', 'POST'])
def form_example():
"""表单提交示例 - 处理GET和POST请求
GET请求: 返回包含表单的HTML页面
POST请求: 处理表单提交的数据
返回:
str: 根据请求类型返回表单页面或处理结果
"""
# request.method: 当前请求的HTTP方法(GET、POST等)
if request.method == 'POST':
# 处理POST请求(表单提交)
# request.form: 包含表单数据的不可变字典
# get('username', '未提供'): 获取表单字段值,如果不存在则返回默认值
username = request.form.get('username', '未提供')
password = request.form.get('password', '未提供')
# 返回处理结果
return f'表单提交成功 - 用户名: {username}, 密码: {password}'
else:
# 处理GET请求,返回表单页面
return '''
<form method="post">
<div>
<label>用户名:</label>
<input type="text" name="username">
</div>
<div>
<label>密码:</label>
<input type="password" name="password">
</div>
<button type="submit">提交</button>
</form>
'''
# 路由:文件上传
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
"""文件上传示例 - 处理文件上传请求
GET请求: 返回文件上传表单
POST请求: 处理上传的文件
返回:
str: 根据请求类型返回上传表单或处理结果
"""
if request.method == 'POST':
# 处理POST请求(文件上传)
# request.files: 包含所有上传文件的不可变字典
# 'file' not in request.files: 检查是否有名为'file'的文件字段
if 'file' not in request.files:
return '没有文件部分'
# 获取上传的文件对象
file = request.files['file']
# 检查文件名是否为空
# 当用户未选择文件但点击提交时,浏览器会发送一个空文件名
if file.filename == '':
return '未选择文件'
# 检查文件是否存在且扩展名是否允许
if file and allowed_file(file.filename):
# secure_filename(): 确保文件名安全,防止路径遍历攻击
# 例如将 "../../../etc/passwd" 转换为 "etc_passwd"
filename = secure_filename(file.filename)
# 构建保存路径并保存文件
# os.path.join(): 连接路径组件,确保跨平台兼容性
file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
# file.save(): 将上传的文件保存到指定路径
file.save(file_path)
# 返回成功消息
return f'文件上传成功: {filename}'
# GET请求返回上传表单
# enctype="multipart/form-data": 必须设置此属性才能上传文件
return '''
<form method="post" enctype="multipart/form-data">
<div>
<label>选择文件:</label>
<input type="file" name="file">
</div>
<button type="submit">上传</button>
</form>
'''
# 路由:JSON响应
@app.route('/json')
def json_example():
"""JSON响应示例 - 返回JSON格式数据
返回:
Response: 包含JSON数据的Flask响应对象
Content-Type自动设置为application/json
"""
# 创建要返回的数据字典
data = {
'name': 'Flask示例',
'version': '1.0',
'features': ['路由', '请求处理', '响应', '文件上传']
}
# jsonify(): 将Python字典转换为JSON响应
# 自动设置Content-Type为application/json
return jsonify(data)
# 路由:重定向示例
@app.route('/redirect-example')
def redirect_example():
"""重定向示例 - 将请求重定向到另一个URL
返回:
Response: 重定向响应,默认状态码为302(临时重定向)
"""
# redirect(): 创建重定向响应
# url_for('index'): 生成index视图函数对应的URL
# url_for()比硬编码URL更灵活,当路由规则改变时不需要修改代码
return redirect(url_for('index'))
# 路由:自定义响应
@app.route('/custom-response')
def custom_response():
"""自定义响应示例 - 创建自定义HTTP响应
返回:
Response: 自定义的Flask响应对象
"""
# make_response(): 创建响应对象
# 参数是响应的主体内容
response = make_response('<h1>这是一个自定义响应</h1>')
# 设置响应头
# response.headers: 响应头字典
# Content-Type: 指定响应的MIME类型
response.headers['Content-Type'] = 'text/html'
# X-Custom-Header: 自定义响应头,可用于传递额外信息
response.headers['X-Custom-Header'] = 'Flask示例'
# 设置Cookie
# set_cookie(): 在响应中设置Cookie
# 参数1: Cookie名称
# 参数2: Cookie值
# 还可以设置max_age, expires, path, domain, secure, httponly等参数
response.set_cookie('username', 'flask_user')
# 设置状态码
# status_code: 响应的HTTP状态码
# 200: 表示请求成功
response.status_code = 200
# 返回响应对象
return response
# 启动应用
# __name__ == '__main__': 确保只有直接运行此脚本时才执行下面的代码
# 当作为模块导入时不会执行
if __name__ == '__main__':
# app.run(): 启动Flask内置的开发服务器
# debug=True: 开启调试模式,启用自动重载和详细错误页面
# host='0.0.0.0': 监听所有网络接口,允许外部访问
# port=5000: 指定服务器端口号
app.run(debug=True, host='0.0.0.0', port=5000)
项目结构
Flask/
├── app.py # 主应用程序文件
├── uploads/ # 上传文件存储目录(自动创建)
└── README.md # 项目说明文档
运行说明
环境准备
- 确保已安装Python(推荐3.7+)
- 安装Flask框架:
pip install flask
启动应用
方法一:直接运行Python文件
python app.py
方法二:使用Flask命令(Windows系统)
set FLASK_APP=app.py
flask run
方法二:使用Flask命令(Linux/Mac系统)
export FLASK_APP=app.py
flask run
访问应用
启动应用后,在浏览器中访问:
http://127.0.0.1:5000/
你将看到主页面,其中包含了所有示例功能的链接,可以点击各个链接进行测试。
学习要点
通过本项目,你可以学习以下Flask知识点:
- Flask应用的创建和配置
- 路由系统和URL规则
- 请求对象的使用
- 响应的生成和处理
- 文件上传的处理
- 自定义URL转换器
扩展学习
完成本示例后,可以尝试:
- 添加模板渲染(使用Jinja2)
- 集成数据库(如SQLAlchemy)
- 添加用户认证(如Flask-Login)
- 创建RESTful API
- 添加表单验证(如Flask-WTF)