这是个 python 的库
安装:
pip install Flask
from flask import Flask //导入flask类 | |
app = Flask(__name__) | |
//创建实例‘app’,__name__是特殊变量,直接执行是__main__,被导入时模块名 | |
//用来Flask是构造函数,传递这个变量是为了让Flask应用能找到这个文件 | |
@app.route('/') //装饰器,里面那个是url,'/'就是指网页根目录,该目录下加载该文件 | |
def hello_world(): | |
return 'Hello, World!' | |
if __name__ == '__main__': //在不是被导入的情况下执行debug | |
app.run(debug=True) //run方法,启动内置的开发服务器,参数表示同时启动调试 |
# 基本概念
路由:指定在特定 url 执行特定函数
@app.route('/') |
视图函数:视图函数是处理请求并返回响应的 Python 函数。它们通常接收请求对象作为参数,并返回响应对象。
//需要导入request类 | |
@app.route('/greet/<name>') | |
def greet(name): | |
return f'Hello, {name}!' |
请求对象:请求对象(request)包含了客户端发送的请求信息
//需要导入request类 | |
@app.route('/submit', methods=['POST']) | |
def submit(): | |
username = request.form.get('username') //获取POST请求的对应字段 | |
return f'Hello, {username}!' |
响应对象:响应对象包含了发送给客户端的响应信息,如状态码、响应头、响应体等。
//需要导入make_response类 | |
@app.route('/custom_response') | |
def custom_response(): | |
response = make_response('This is a custom response!') //创建自定义响应对象 | |
response.headers['X-Custom-Header'] = 'Value' //创建响应头 | |
return response |
模板:Flask 使用 Jinja2 模板引擎来渲染 HTML 模板。模板允许你将 Python 代码嵌入到 HTML 中,从而动态生成网页。
//需要导入render_template类 | |
@app.route('/hello/<name>') | |
def hello(name): | |
return render_template('hello.html', name=name) | |
//后面那个是传递给模板的变量,注意模板要在templates文件夹中 |
<h1>Hello, !</h1> <--模板中使用参数--> |
应用工厂:应用工厂是一个 Python 函数,它创建并返回一个 Flask 应用实例。这允许你配置和初始化你的应用,并且可以创建多个应用实例。
from flask import Flask | |
def create_app(config_name): | |
app = Flask(__name__) | |
app.config.from_object(config_name) //这个方法从指定对象加载配置 | |
from . import routes //从当前包中导入模块routes.py | |
app.register_blueprint(routes.bp) //把其中的蓝图注册到该应用,模块化开发用 | |
return app |
配置对象:有一个配置对象,你可以使用它来设置各种配置选项,如数据库连接字符串、调试模式等。
//上面的config_name | |
class Config: | |
DEBUG = True | |
SECRET_KEY = 'mysecretkey' //密钥,加密会话用 | |
SQLALCHEMY_DATABASE_URI = 'sqlite:///mydatabase.db' //数据库url | |
STATIC_FOLDER = 'static' //静态文件存储路径 | |
TEMPLATE_FOLDER = 'templates' //蓝图存储路径 | |
//这些玩意儿可以Flask(__name__,xxx)来指定。 |
蓝图:一个组织代码的方式,它允许你将相关的视图函数、模板和静态文件组织在一起,并且可以在多个应用中重用。
//需要导入Blueprint | |
bp = Blueprint('main', __name__) //蓝图名+当前模块名 | |
@bp.route('/') | |
def home(): | |
return 'Home Page' |
from flask import Flask | |
from .routes import bp as main_bp | |
//从当前包的 routes.py 模块里导入 bp 对象,并将其重命名为 main_bp。 | |
//包是可以嵌套的..表示父包,可以认为包是一个存储模块的文件夹(所以用.或者..实际上等同于用相对路径) | |
def create_app(): | |
app = Flask(__name__) | |
app.register_blueprint(main_bp) | |
return app |
静态文件:静态文件是不会被服务器端执行的文件,如 CSS、JavaScript 和图片文件。
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}"> | |
{% raw %} | |
//回去static目录找那个css文件 | |
//这个通常是被导入的模板里的 | |
//将静态文件放在 static 文件夹中,Flask 会自动提供服务(如果你没改) |
扩展:有其他插件,难说~~
会话:存储用户信息,用户浏览应用时可以记住他们的状态。
就是 session,存储在 cookie
这里 session 对象用于存取对话数据
from flask import session | |
#可以使用 Python 内置的 secrets 模块生成一个强随机性的密钥 | |
#import secrets; print(secrets.token_hex()) | |
app.secret_key = 'your_secret_key_here' | |
@app.route('/set_session/<username>') | |
def set_session(username): | |
session['username'] = username //把变量username的值存储在会话中,键为username | |
return f'Session set for {username}' | |
@app.route('/get_session') | |
def get_session(): | |
username = session.get('username') //读取刚刚那个键的值 | |
return f'Hello, {username}!' if username else 'No session data' |
Flask 的会话默认是永久的,但可以通过设置 session.permanent = True
来明确指定,并且可以通过 app.permanent_session_lifetime
来设置会话的过期时间。
错误处理:可以定义错误处理函数。
@app.errorhandler(404) | |
def page_not_found(e): | |
return 'Page not found', 404 | |
@app.errorhandler(500) | |
def internal_server_error(e): | |
return 'Internal server error', 500 |
# 一个玩意儿
from flask import Flask, session, redirect, url_for, render_template_string | |
app = Flask(__name__) | |
app.secret_key = 'your_secret_key' | |
@app.route('/') //定义首页路由 | |
def index(): | |
username = session.get('username') | |
if username: | |
return f'Hello, {username}!' | |
else: | |
return 'You are not logged in.' | |
@app.route('/login/<username>') //定义登录路由 | |
def login(username): | |
session['username'] = username | |
return redirect(url_for('index')) | |
@app.route('/logout') //定义注销路由 | |
def logout(): | |
session.pop('username', None) //移除username键 | |
return redirect(url_for('index')) //重定向回首页 | |
if __name__ == '__main__': | |
app.run(debug=True) |
# 项目结构
my_flask_app/ │ ├── app.py └── requirements.txt
my_flask_app/ │ ├── app/ │ ├── __init__.py │ ├── routes.py │ └── models.py │ ├── config.py ├── requirements.txt └── run.py
my_flask_app/ │ ├── app/ //包含主要代码 │ ├── __init__.py //3.0+版本不强制有,初始化Flask应用和配置扩展 │ ├── routes/ //应用路由和视图函数,这里用一个包代替上面的一个模块 │ │ ├── __init__.py │ │ ├── main.py //主模块路由 │ │ └── auth.py //认证相关路由 │ ├── models/ //数据库相关 │ │ ├── __init__.py │ │ └── user.py //用户模型 │ ├── templates/ //存储HTML模板 │ │ ├── layout.html │ │ └── home.html │ └── static/ │ ├── css/ │ └── js/ │ ├── config.py ├── requirements.txt //列出依赖库 ├── migrations/ //数据库迁移文件 │ └── ... └── run.py //用于启动Flask应用
目录咯~
run.py 示例
from app import create_app | |
app = create_app() | |
if __name__ == '__main__': | |
app.run(debug=True) |
route.py 示例
from flask import Blueprint | |
bp = Blueprint('main', __name__) | |
@bp.route('/') | |
def home(): | |
return 'Hello, World!' |
_init_.py 示例
from flask import Flask | |
def create_app(): | |
app = Flask(__name__) | |
app.config.from_object('config.Config') | |
from . import routes | |
app.register_blueprint(routes.bp) | |
return app |
# flask 路由
# 动态部分
@app.route('/greet/<name>') | |
//这样可以将这一部分当做参数传给函数,比如: | |
def greet(name): | |
return f'Hello, {name}!' |
# 路由规则
路由规则支持不同类型的参数和匹配规则
字符串(默认),整数(<int:name>),浮点数(<float:value>),路径(<path:name>)
@app.route('/user/<int:user_id>') //这样就不会全部都当作内容 | |
def user_profile(user_id): | |
return f'User ID: {user_id}' | |
@app.route('/files/<path:filename>') | |
def serve_file(filename): | |
return f'Serving file: {filename}' |
# 请求方法
@app.route('/submit', methods=['POST']) |
# 路由转换器
还是那仨
@app.route('/items/<int:item_id>/details') |
# 路由函数返回
通过视图函数(基本等同,只是路由函数要 url 映射)可以返回:
# 路由优先级
按照定义顺序
# 视图函数
# 接受数据
@app.route('/greet/<name>') #url | |
@app.route('/submit', methods=['POST']) #POST | |
def submit(): | |
username = request.form.get('username') | |
return f'Form submitted by {username}!' | |
@app.route('/search') #GET | |
def search(): | |
query = request.args.get('query') //获取 GET 请求中的查询参数query | |
return f'Search results for: {query}' |
# 返回响应
return 'This is a simple message.' | |
return render_template('hello.html', name=name) //记得导入render_template | |
def api_data(): //要导入jsonify | |
data = {'key': 'value','key2':'value2'} | |
return jsonify(data) | |
//自动序列化,将 Python 数据类型(如字典、列表、字符串等,但不是全部)转换为 JSON 格式 | |
//会自动设置Content—Type,支持多参数,自动合并为一个json对象 | |
比如: | |
return jsonify( | |
message="Hello, World!", | |
status=200, | |
data=[1, 2, 3, 4] | |
) |
还可以用来:
设置状态码
return jsonify({"error": "Not Found"}), 404返回自定义响应头
def custom_response(): response = Response('Custom response with headers', status=200)#创建自定义响应对象
response.headers['X-Custom-Header'] = 'Value'return response
# 处理请求和响应
视图函数可以访问请求对象
使用 request 对象来获取请求的信息,使用 make_response 来创建自定义响应
def info(): | |
user_agent = request.headers.get('User-Agent') //有点规律,我说命名 | |
return f'Your user agent is {user_agent}' |
def custom_header(): | |
response = make_response('Response with custom header') | |
response.headers['X-Custom-Header'] = 'Value' | |
return response |
# 处理错误
@app.route('/divide/<int:x>/<int:y>') | |
def divide(x, y): | |
try: | |
result = x / y | |
return f'Result: {result}' | |
except ZeroDivisionError: | |
return 'Error: Division by zero', 400 //当然,状态码,可自定义 | |
//可以返回jsonify格式: | |
return jsonify({ | |
'error': 'Division by zero', | |
'message': 'The divisor cannot be zero.' | |
}), 400 | |
结构化响应: | |
def error_response(message, status_code): | |
return jsonify({ | |
'error': { | |
'message': message, | |
'status_code': status_code | |
} | |
}), status_code | |
使用时: | |
return error_response('Invalid email format', 400, 'INVALID_EMAIL') |
全局错误处理: | |
@app.errorhandler(404) //定义处理404的函数 | |
def not_found(error): | |
return 'Page not found', 404 |
# 视图函数的装饰器
-
@app.before_request
:在每个请求处理之前运行的函数。 -
@app.after_request
:在每个请求处理之后运行的函数。 -
@app.teardown_request
:在请求结束后运行的函数,用于清理工作。
# 视图函数返回的状态码
指定状态码(就上面那个):
return 'Everything is OK', 200 |
返回带状态码的对象:
return Response('An error occurred', status=500) |
# 模板渲染
# 创建
{{ title }} 和 {{ name }} 是模板占位符,将在渲染时被替换成实际的值
return render_template('index.html', title='Welcome Page', name='John Doe') //可以传入对象 |
# 继承
基础模板:
<title>{% block title %}My Website{% endblock %}</title> | |
<main> | |
{% block content %}{% endblock %} 可替换区域 | |
</main> |
子模板:
{% raw %}
{% extends "base.html" %} //继承基础模板
{% block title %}Home Page{% endblock %} //重写替换区域的内容
{% block content %}
Welcome to the Home Page!
Content goes here.
{% endblock %}
{% raw %}
# 控制结构
{% if user %}
{% else %}
{% endif %}
{% for item in items %}
{% endfor %}
# 过滤器
处理变量用
{{ name|capitalize }}:将 name 变量的值首字母大写。
{{ price|round(2) }}:将 price 变量的值四舍五入到小数点后两位。
# 可能有用的
字符串处理
过滤器 | 功能描述 | 示例输入 | 输出结果 |
---|---|---|---|
lower |
转换为小写 | "Hello" |
"hello" |
upper |
转换为大写 | "world" |
"WORLD" |
title |
每个单词首字母大写 | "hello world" |
"Hello World" |
trim |
去除前后空格 | " flask " |
"flask" |
striptags |
去除 HTML/XML 标签 | "Hello Flask" |
"Hello Flask" |
truncate |
截断字符串(超出长度后追加省略号) | "long text here" (length=5) |
"long..." |
replace(a, b) |
替换字符串中的子串 | "hello", "h", "j" |
"jello" |
safe |
标记为安全内容(不转义 HTML) | "Hello Flask" |
渲染为 Flask |
# 数值操作
过滤器 | 功能描述 | 示例输入 | 输出结果 |
---|---|---|---|
round |
四舍五入 | 3.14159 |
3 |
int |
转换为整数 | "42" |
42 |
float |
转换为浮点数 | "3.14" |
3.14 |
format |
格式化数值 | 1000, "0,.2f" |
"1,000.00" |
default |
设置默认值(变量不存在时使用) | undefined_var, "N/A" |
"N/A" |
# 日期时间
过滤器 | 功能描述 | 示例输入(Python datetime 对象) | 输出结果 |
---|---|---|---|
datetimeformat |
格式化日期时间 | now(), "%Y-%m-%d %H:%M" |
"2023-10-01 14:30" |
date |
提取日期部分 | now() |
"2023-10-01" |
time |
提取时间部分 | now() |
"14:30:45" |
timedelta |
计算时间差 | start_date, end_date |
"3 days, 2 hours" |
# 列表 / 字典操作
过滤器 | 功能描述 | 示例输入 | 输出结果 |
---|---|---|---|
length |
获取列表 / 字符串长度 | [1, 2, 3] |
3 |
sort |
对列表排序 | [3, 1, 2] |
[1, 2, 3] |
reverse |
反转列表 | [1, 2, 3] |
[3, 2, 1] |
join |
连接列表元素 | ["a", "b"], "-" |
"a-b" |
keys |
获取字典的键列表 | {"a": 1, "b": 2} |
["a", "b"] |
values |
获取字典的值列表 | {"a": 1, "b": 2} |
[1, 2] |
# 逻辑判断
过滤器 | 功能描述 | 示例输入 | 输出结果 |
---|---|---|---|
if |
条件判断 | user.is_authenticated |
根据条件渲染内容 |
default |
变量不存在时使用默认值 | username, "Guest" |
"Guest" (若 username 未定义) |
none |
判断是否为 None |
value |
true 或 false |
defined |
判断变量是否存在 | undefined_var |
false |
# 其他实用过滤器
过滤器 | 功能描述 | 示例输入 | 输出结果 |
---|---|---|---|
pprint |
格式化输出(用于调试) | {"a": 1, "b": 2} |
美观缩进的 JSON 格式 |
markdown |
将 Markdown 转换为 HTML | "# Hello\n**Flask**" |
渲染后的 HTML 内容 |
urlencode |
对 URL 进行编码 | "https://example.com?q=test" |
编码后的字符串 |
regex_replace |
使用正则表达式替换 | "a1b2c3", "[0-9]", "" |
"abc" |
# 链式调用示例
{{ " hello world "|trim|title|replace(" ", "-") }} | |
<!-- 输出:"Hello-World" --> |
# 八。自定义过滤器
在 Flask 中可以注册自定义过滤器:
@app.template_filter('reverse') | |
def reverse_filter(s): | |
return s[::-1] | |
<!-- 模板中使用 --> | |
<!--swig18--> → "olleh" |
# 宏和模板包含
将在一个 html 文件中插入另一个的内容
# 创建宏
{% raw %} | |
{% macro render_item(item) %}
| |
{% raw %} |
{% raw %} | |
{% from "macros.html" import render_item %} //导入宏 | |
{% for item in items %}
{{ render_item(item) }} //用宏渲染每个item
{% endfor %} | |
{% raw %} |
# 模板上下文
传递的参数可以直接用
# 表单处理
获取就是上面的 request.form.get('name')
[Flask-WTF 表单]( Flask 表单处理 | 菜鸟教程 ),用于防 CSRF, 可以进行表单验证。PS: 懒得看了~(这就是不学的理由?)
# 文件上传
通过 request.files 访问 。改一下编码类型(这真的需要自己改么......)
from flask import Flask, request, redirect, url_for | |
app = Flask(__name__) | |
app.secret_key = 'your_secret_key' | |
@app.route('/upload', methods=['POST']) | |
def upload(): | |
file = request.files.get('file') | |
if file: | |
filename = file.filename //获取原始文件名 | |
file.save(f'uploads/{filename}') | |
return f'File uploaded successfully: {filename}' | |
return 'No file uploaded' | |
if __name__ == '__main__': | |
app.run(debug=True) |
通过 request.files.get('file')
尝试从请求中获取名为 file
的文件对象。 request.files
是一个字典,存储了所有上传的文件
使用 file.save()
方法将文件保存到 uploads
目录下,文件名保持不变