flask教程
项目结构
中型
my_flask_project/
├── app/ # 核心应用文件夹
│ ├── __init__.py # 应用初始化
│ ├── routes.py # 路由定义
│ ├── models.py # 数据模型(如需要)
│ ├── templates/ # HTML 模板
│ │ └── index.html
│ └── static/ # 静态文件
│ ├── css/
│ │ └── style.css
│ └── js/
│ └── script.js
├── config.py # 配置文件
├── run.py # 启动文件
└── requirements.txt # 依赖文件
app/__init__.py
在 __init__.py
中创建并初始化 Flask 应用,加载配置,并从 routes.py
注册路由。
from flask import Flask
def create_app():
app = Flask(__name__)
app.config.from_object('config.Config') # 加载配置
with app.app_context():
# 导入并注册路由
from . import routes
return app
- 说明:
create_app
函数用于创建和配置应用实例。app.app_context()
确保在应用上下文中导入路由。
app/routes.py
定义项目的路由,所有路由相关的逻辑放在这个文件中。
from flask import render_template, current_app as app
@app.route('/')
def home():
return render_template('index.html')
- 说明:
app.route('/')
是根路径的路由,返回index.html
模板页面。
app/models.py
(可选)
如果项目需要数据库模型,可以在此文件中定义。例如:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(150), nullable=False, unique=True)
config.py
配置文件,用于管理全局配置(例如密钥、数据库 URI 等)。将敏感信息存储在环境变量中更安全。
import os
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY') or 'your_secret_key'
SQLALCHEMY_DATABASE_URI = 'sqlite:///site.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
app/templates/index.html
HTML 模板文件示例。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Flask App</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<h1>Welcome to My Flask App</h1>
<p>Hello, Flask with modular structure!</p>
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
</body>
</html>
app/static/css/style.css
简单的 CSS 文件,用于为页面增加样式。
/* static/css/style.css */
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
}
app/static/js/script.js
简单的 JavaScript 文件。
// static/js/script.js
console.log("Welcome to My Flask App with modular structure!");
run.py
项目的启动文件,通过调用 create_app
函数启动应用。
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
- 说明:
run.py
是整个项目的入口文件,使用app.run(debug=True)
启动应用程序。
requirements.txt
包含项目依赖。
大型
my_flask_project/
├── app/
│ ├── __init__.py # 初始化应用程序和配置
│ ├── routes.py # 路由定义
│ ├── models.py # 数据库模型定义
│ ├── templates/ # HTML 模板文件
│ │ └── base.html
│ ├── static/ # 静态文件(CSS、JS、图片等)
│ │ ├── css/
│ │ │ └── style.css
│ │ ├── js/
│ │ └── images/
│ └── blueprints/ # 各个功能模块的蓝图
│ ├── __init__.py
│ ├── user/ # 用户模块
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── templates/
│ └── admin/ # 管理员模块
│ ├── __init__.py
│ ├── routes.py
│ └── templates/
├── migrations/ # 数据库迁移文件(使用 Flask-Migrate)
├── tests/ # 测试代码
│ ├── __init__.py
│ └── test_app.py
├── config.py # 配置文件
├── manage.py # 启动、管理和迁移命令
└── requirements.txt # 依赖包
**
app/
**:主要应用程序文件夹,包含所有核心代码。- **
__init__.py
**:初始化 Flask 应用、加载配置和注册蓝图。 - **
routes.py
**:定义全局路由。 - **
models.py
**:定义数据库模型。 - **
templates/
**:存储 HTML 模板。 - **
static/
**:存储静态文件,如 CSS、JavaScript 和图片。 - **
blueprints/
**:存储不同功能模块的蓝图,每个模块可以有自己的routes.py
和templates/
文件夹。
**
migrations/
**:数据库迁移文件(如使用 Flask-Migrate 时生成)。**
tests/
**:测试文件夹,用于单元测试或集成测试。**
config.py
**:存储配置文件,如数据库连接和应用的全局设置。**
manage.py
**:用于管理项目的文件,可添加自定义命令,如启动服务器、初始化数据库等。**
requirements.txt
**:记录项目的所有依赖包。- **
路由
1. 基本路由
最简单的路由是将一个 URL 映射到一个视图函数。可以使用 @app.route()
装饰器来定义路由。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "Welcome to the homepage!"
@app.route('/about')
def about():
return "This is the about page."
@app.route('/')
:当用户访问根路径(如http://localhost:5000/
)时,执行home
函数。@app.route('/about')
:访问/about
时,执行about
函数。
2. 动态路由
可以在路由中添加动态部分,用来接收 URL 中的参数。动态部分用尖括号 <...>
表示,Flask 会自动将 URL 中的值传递给视图函数。
@app.route('/user/<username>')
def show_user(username):
return f"Hello, {username}!"
- 访问
/user/john
时,会输出Hello, john!
。 <username>
是一个动态参数,视图函数show_user
将接收username
的值。
指定数据类型
默认情况下,Flask 会将 URL 参数作为字符串处理。如果需要其他类型的数据,可以在尖括号内指定:
@app.route('/post/<int:post_id>')
def show_post(post_id):
return f"Post ID is {post_id}"
<int:post_id>
指定了post_id
必须是整数,访问/post/5
会返回Post ID is 5
。- 常用的数据类型有:
<int:variable>
:整数<float:variable>
:浮点数<path:variable>
:字符串(允许包含/
)
3. 多种请求方法
默认情况下,Flask 路由只响应 GET
请求。如果需要处理其他 HTTP 方法(如 POST
、PUT
、DELETE
等),可以通过 methods
参数指定。
@app.route('/submit', methods=['GET', 'POST'])
def submit():
if request.method == 'POST':
return "Form submitted!"
return "Please submit the form."
methods=['GET', 'POST']
:允许submit
路由响应GET
和POST
请求。- 使用
request.method
判断请求类型并做不同的处理。
4. 路由别名(URL 别名)
可以使用 url_for
函数生成路由的 URL,避免硬编码 URL。在视图函数上使用 endpoint
参数,可以给路由一个别名,用于简化 url_for
函数调用。
from flask import url_for
@app.route('/profile/<username>', endpoint='user_profile')
def profile(username):
return f"User: {username}"
# 使用 url_for 动态生成 URL
@app.route('/redirect_to_profile')
def redirect_to_profile():
return redirect(url_for('user_profile', username='john'))
- 访问
/redirect_to_profile
会重定向到/profile/john
。
5. 重定向与错误处理
可以通过 redirect
实现重定向,或用 abort
函数处理错误。
from flask import redirect, abort
@app.route('/old-url')
def old_url():
# 重定向到新的 URL
return redirect(url_for('new_url'))
@app.route('/new-url')
def new_url():
return "This is the new URL."
@app.route('/secret')
def secret():
abort(403) # 返回 403 错误
redirect(url_for('new_url'))
:将用户重定向到new_url
视图。abort(403)
:返回 403 错误页面。
6. 带查询参数的路由
查询参数一般附加在 URL 的末尾,例如 http://localhost:5000/search?query=flask
。可以通过 request.args
获取这些参数。
from flask import request
@app.route('/search')
def search():
query = request.args.get('query')
return f"Search results for: {query}"
request.args.get('query')
:获取查询参数query
的值。
7. 路由分组(蓝图)
如果应用较大,可以将路由划分为不同的模块(称为“蓝图”),以提高代码组织性。以下是一个简单的蓝图示例。
创建蓝图文件 app/user.py
:
from flask import Blueprint
user_bp = Blueprint('user', __name__)
@user_bp.route('/<username>')
def profile(username):
return f"User Profile for {username}"
注册蓝图到应用中 app/__init__.py
:
from flask import Flask
from .user import user_bp
def create_app():
app = Flask(__name__)
app.register_blueprint(user_bp, url_prefix='/user') # 注册蓝图
return app
url_prefix='/user'
:访问/user/<username>
时,会调用user_bp
蓝图中的profile
路由。- 蓝图让大型应用代码更清晰。
8. 格式化
from flask import jsonify
@app.route('/json')
def json_data():
data = {"name": "Flask", "version": "2.0"}
return jsonify(data)
9.视图函数的装饰器
除了 @app.route,Flask 还支持其他装饰器,用于实现更复杂的功能。
- **
@app.before_request
**:在每个请求处理之前运行的函数。 - **
@app.after_request
**:在每个请求处理之后运行的函数。 - **
@app.teardown_request
**:在请求结束后运行的函数,用于清理工作。
示例装饰器使用:
@app.before_request
def before_request():
print('Before request')
@app.after_request
def after_request(response):
print('After request')
return response
@app.teardown_request
def teardown_request(exception):
print('Teardown request')
完整示例
以下是一个包含多种路由定义方式的完整示例:
from flask import Flask, request, redirect, url_for, abort, jsonify
app = Flask(__name__)
@app.route('/')
def home():
return "Welcome to the homepage!"
@app.route('/user/<username>')
def show_user(username):
return f"Hello, {username}!"
@app.route('/post/<int:post_id>')
def show_post(post_id):
return f"Post ID is {post_id}"
@app.route('/submit', methods=['GET', 'POST'])
def submit():
if request.method == 'POST':
return "Form submitted!"
return "Please submit the form."
@app.route('/search')
def search():
query = request.args.get('query')
return f"Search results for: {query}"
@app.route('/json')
def json_data():
data = {"name": "Flask", "version": "2.0"}
return jsonify(data)
@app.route('/old-url')
def old_url():
return redirect(url_for('home'))
@app.route('/secret')
def secret():
abort(403)
Flask 模板渲染
在 Flask 中,模板渲染是生成动态 HTML 页面的一种方法。Flask 使用 Jinja2 模板引擎来帮助你在 HTML 中插入变量、控制结构(如条件判断、循环)等内容,以便动态生成页面。
1. 设置模板文件夹
在 Flask 项目中,默认的模板文件夹是 templates
,建议将所有 HTML 模板文件放在这个文件夹中。Flask 会自动寻找并渲染该目录中的模板文件。
2. 创建基本 HTML 模板
假设我们在 templates/index.html
中创建了一个基本的 HTML 模板文件:
<!-- templates/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h1>{{ heading }}</h1>
<p>{{ content }}</p>
</body>
</html>
在这个模板中:
{{ title }}
、{{ heading }}
和{{ content }}
是变量占位符,在渲染模板时会被 Flask 替换成实际的值。
3. 渲染模板
在 Flask 中,可以使用 render_template
函数来渲染 HTML 模板,并将变量传递给模板。下面是一个简单的视图函数,渲染上面的 index.html
模板。
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
return render_template('index.html', title="Home Page", heading="Welcome to My Website", content="This is the home page content.")
render_template('index.html', ...)
:render_template
函数会在templates
文件夹中找到index.html
文件,并将指定变量传入模板。title="Home Page"
:将title
变量的值传入模板,模板中的{{ title }}
将被替换为Home Page
。
4. 模板变量和控制结构
Jinja2 模板支持在 HTML 中使用变量、控制结构(条件、循环)等操作。
变量
使用双大括号 {{ ... }}
在模板中插入变量。
<p>Hello, {{ name }}!</p>
条件语句
使用 {% if ... %}` 和 `{% endif %}
添加条件逻辑:
{% if user_is_logged_in %}
<p>Welcome back, {{ username }}!</p>
{% else %}
<p>Please log in to access your account.</p>
{% endif %}
循环
使用 {% for ... in ... %}` 和 `{% endfor %}
添加循环:
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
5. 继承与块
Jinja2 支持模板继承,可以创建一个基础模板供其他模板继承。可以将公共结构(如导航栏、页脚等)放在基础模板中,然后在子模板中覆盖特定部分。
基础模板 templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}My Website{% endblock %}</title>
</head>
<body>
<header>
<h1>My Website</h1>
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
<p>© 2024 My Website</p>
</footer>
</body>
</html>
{% block title %}` 和 `{% block content %}` 是块占位符,子模板可以覆盖这些内容。 #### 子模板 `templates/index.html`
:覆盖了基础模板中的
- `{% extends "base.html" %}` 表示继承 `base.html` 模板。 - `{% block title %}Home Page{% endblock %}{% extends "base.html" %} {% block title %}Home Page{% endblock %} {% block content %} <h2>Welcome to the Home Page</h2> <p>This is some content specific to the home page.</p> {% endblock %}
title
块。{% block content %}...{% endblock %}
:覆盖了基础模板中的content
块。
6. 使用静态文件
Flask 默认将静态文件放在 static
文件夹中,例如 CSS、JavaScript 文件等。在模板中,可以通过 url_for('static', filename='...')
生成静态文件的 URL。
假设有一个 CSS 文件 static/style.css
,可以在模板中引入:
<!-- 在 base.html 中引入 CSS 文件 -->
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
7. 完整示例
以下是包含基础模板、变量、循环、条件的完整 Flask 应用示例。
项目结构
my_flask_app/
├── app.py
├── templates/
│ ├── base.html
│ ├── index.html
└── static/
└── style.css
app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
items = ["Item 1", "Item 2", "Item 3"]
user_is_logged_in = True
return render_template('index.html', title="Home Page", items=items, user_is_logged_in=user_is_logged_in, username="John Doe")
templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}My Website{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<header>
<h1>My Website</h1>
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
<p>© 2024 My Website</p>
</footer>
</body>
</html>
templates/index.html
{% extends "base.html" %}
{% block title %}Home Page{% endblock %}
{% block content %}
<h2>Welcome to the Home Page</h2>
{% if user_is_logged_in %}
<p>Welcome back, {{ username }}!</p>
{% else %}
<p>Please log in to access your account.</p>
{% endif %}
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endblock %}
static/style.css
/* 示例样式 */
body {
font-family: Arial, sans-serif;
}
header {
background-color: #333;
color: #fff;
padding: 1em;
text-align: center;
}
footer {
background-color: #333;
color: #fff;
padding: 0.5em;
text-align: center;
}
Flask 表单处理
在 Flask 中,表单处理是一个常见的功能,它涉及接收用户输入、验证数据以及相应地进行处理。Flask 提供了 Flask-WTF
扩展,使得表单的创建、验证和处理变得更加简单和强大。下面将详细介绍如何在 Flask 中处理表单,包括安装 Flask-WTF、创建表单、验证表单、显示表单错误和处理表单数据。
1. 安装 Flask-WTF
在开始之前,你需要确保安装了 Flask-WTF
。可以通过 pip
进行安装:
pip install Flask-WTF
2. 创建 Flask 应用
创建一个简单的 Flask 应用并设置基本配置。
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key' # 设置安全密钥
3. 创建表单类
使用 Flask-WTF
创建表单类,定义所需的字段和验证规则。
class MyForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
submit = SubmitField('Submit')
StringField
:表示一个文本输入字段。DataRequired()
:确保字段不为空。
4. 渲染表单
在视图函数中实例化表单并传递给模板。
@app.route('/', methods=['GET', 'POST'])
def home():
form = MyForm()
if form.validate_on_submit(): # 验证表单数据
username = form.username.data # 获取输入的用户名
return f'Hello, {username}!'
return render_template('index.html', form=form)
validate_on_submit()
:检查请求方法是否为 POST 并验证表单数据。form.username.data
:访问用户输入的值。
5. 创建模板
在 templates
文件夹中创建一个模板 index.html
,用于显示表单。
<!-- templates/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flask Form Example</title>
</head>
<body>
<h1>Enter your username</h1>
<form method="POST">
{{ form.hidden_tag() }} <!-- 防止 CSRF 攻击 -->
{{ form.username.label }} {{ form.username(size=20) }}<br>
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
{{ form.submit() }}
</form>
</body>
</html>
{{ form.hidden_tag() }}
:生成隐藏的 CSRF 令牌,增强安全性。- 使用
{% for error in form.username.errors %}
循环显示字段的验证错误。
6. 处理表单错误
如果表单验证失败,Flask-WTF 会自动将错误信息存储在字段的 errors
属性中。在模板中,可以通过条件判断显示相应的错误消息。
7. 完整示例
以下是一个完整的 Flask 应用示例,展示了如何使用 Flask-WTF 处理表单。
项目结构
my_flask_app/
├── app.py # Flask 应用主文件
└── templates/
└── index.html # 表单模板
app.py
码from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key' # 设置安全密钥
class MyForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
submit = SubmitField('Submit')
@app.route('/', methods=['GET', 'POST'])
def home():
form = MyForm()
if form.validate_on_submit(): # 验证表单数据
username = form.username.data # 获取输入的用户名
return f'Hello, {username}!'
return render_template('index.html', form=form)
if __name__ == '__main__':
app.run(debug=True)
templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flask Form Example</title>
</head>
<body>
<h1>Enter your username</h1>
<form method="POST">
{{ form.hidden_tag() }} <!-- 防止 CSRF 攻击 -->
{{ form.username.label }} {{ form.username(size=20) }}<br>
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
{{ form.submit() }}
</form>
</body>
</html>
8. 添加更多字段和验证器
可以使用 WTForms
提供的多种字段类型和验证器来扩展表单功能。例如,可以添加 EmailField
、PasswordField
、SelectField
等。
from wtforms import EmailField, PasswordField, SelectField
class ExtendedForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
email = EmailField('Email', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
options = SelectField('Options', choices=[('opt1', 'Option 1'), ('opt2', 'Option 2')])
submit = SubmitField('Submit')
9. 处理文件上传
Flask-WTF 也支持文件上传,可以使用 FileField
。
from wtforms import FileField
class UploadForm(FlaskForm):
file = FileField('File')
submit = SubmitField('Upload')
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
form = UploadForm()
if form.validate_on_submit():
file = form.file.data
# 处理文件上传
return f'File {file.filename} uploaded successfully!'
return render_template('upload.html', form=form)
10. 保护表单安全
使用 SECRET_KEY
保护表单,防止 CSRF 攻击,确保所有表单都使用 form.hidden_tag()
生成 CSRF 令牌。