目录标题
- 1. Flask应用的基本组成部分
- 1.1 路由(Routing)
- 1.2 视图函数(View Function)
- 1.3 请求(Request)
- 1.4 响应(Response)
- 2. 模板引擎Jinja2的使用
- 2.1 入门案例
- 2.2 条件判断
- 2.3 循环遍历
- 2.4 过滤器
- 2.5 宏
- 2.6 定义临时变量
- 2.7 定义模板
- 3. Flask-WTF表单处理和验证
- 3.1 安装 Flask-WTF
- 3.2 定义表单类
- 3.2.1 字段类型和验证器
- 3.2.2 综合案例
- 3.3 渲染表单
- 3.4 处理表单提交
- 4. 数据库操作和SQLAlchemy
- 4.1 安装
- 4.2 配置数据库连接
- 4.3 定义数据模型类
- 4.4 数据操作
1. Flask应用的基本组成部分
Flask应用的基本组成部分包括路由、视图函数、请求和响应。
1.1 路由(Routing)
路由(Routing)是将URL映射到相应的视图函数(View Function)上的过程。
在Flask中,可以通过装饰器来定义路由,如下所示:
from flask import Flask
app = Flask(__name__) # 实例化一个Flask对象,最基本的写法
@app.route('/')
def index():
return 'Hello, World!'
if __name__ == "__main__":
app.run()
在Python中,装饰器(decorator)是一种特殊的函数,用于修改或增强其他函数的功能。装饰器是通过在被装饰函数的定义前加上
@
符号,将被装饰函数传递给装饰器函数作为参数来实现的。
在上面的代码中,我们通过app.route
装饰器定义了一个路由,将/
映射到index
函数上。当用户在浏览器中访问/
时,就会执行index
函数,并返回'Hello, World!'
这个字符串。
1.2 视图函数(View Function)
上面的例子中,index
函数就是一个视图函数。
Flask应用中处理请求并返回响应的函数。视图函数通常会接收一些参数(如URL中的参数、POST请求中的表单数据等),并根据这些参数进行处理,最后返回一个响应(如HTML页面、JSON数据等)。
1.3 请求(Request)
请求是Flask应用中接收客户端发来的数据的对象。
每次客户端发送一个HTTP请求时,Flask将会创建一个request
对象。
在视图函数中,我们可以通过request
对象获取客户端提交的数据(如表单数据、URL 参数等)。例如,下面的代码中,我们通过request.args.get
方法获取了URL参数中的name
参数:
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def index():
name = request.args.get('name', 'World')
return f'Hello, {name}!'
在浏览器中访问/?name=Flask
,就会返回'Hello, Flask!'
这个字符串。
下面是request一些常用的方法和属性:
request.method
:HTTP请求方法,如 GET、POST、PUT、DELETE 等。request.args
:获取查询参数,返回一个不可变字典。request.form
:获取表单参数,返回一个不可变字典。request.files
:获取上传的文件,返回一个不可变字典。request.headers
:获取请求头,返回一个字典。request.cookies
:获取请求中的 cookies,返回一个字典。request.remote_addr
:获取客户端的 IP 地址。request.path
:获取请求路径,不包含查询参数。request.url
:获取完整的请求 URL。request.is_xhr
:判断请求是否是 AJAX 请求。
提取方法 | 描述 |
---|---|
request.cookies | 提取cookie字典信息 |
request.args.get(“name”) | 查询字符串参数 /user?name=curry&age=18 |
request.form.get(“name”) | 表单数据 {“name”: “james”, “age”: 38} |
request.json.get(“name”) | json格式字符串参数 |
参考连接:http://t.csdn.cn/kFwUR
1.4 响应(Response)
响应是Flask应用中返回给客户端的数据。
在视图函数中,我们可以通过return
语句返回响应。
响应可以是各种格式的数据,如HTML页面、JSON数据、图片、文件等。例如,下面的代码中,我们返回了一个HTML页面:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '<html><body><h1>Hello, World!</h1></body></html>'
在浏览器中访问 /
,就会显示一个标题为'Hello, World!'
的 HTML 页面。
在Flask中,我们可以使用make_response()
函数来创建一个响应对象,并可以通过设置其内容、状态码、头部等属性来进行自定义。
例如,以下代码定义了一个包含自定义内容和状态码的响应:
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/')
def hello_world():
response = make_response('Hello World!', 200)
# 这里设置了一个自定义的响应头,键为 'X-My-Header',值为 'my-value'
response.headers['X-My-Header'] = 'my-value'
return response
下面是response一些常用的方法和属性:
response.status_code
:HTTP 响应状态码,如 200、404 等。response.headers
:HTTP 响应头,可以通过该属性设置自定义的响应头,返回一个字典。response.content_type
:HTTP 响应内容的 MIME 类型,如 text/html、application/json 等。response.data
:HTTP 响应内容,返回一个字节串。response.set_cookie()
:设置 cookie。response.delete_cookie()
:删除 cookie。response.make_response()
:创建一个 Response 对象,可以通过该方法自定义响应内容和响应头。
官网地址:https://flask.palletsprojects.com/en/latest/
2. 模板引擎Jinja2的使用
Jinja2中文文档_w3cschool
Jinja2是Flask默认的模板引擎,它是一种基于Python语言的模板引擎,具有简单、高效、安全等特点。
Jinja2支持模板继承、变量替换、条件判断、循环遍历等常用的模板操作。
在Flask中,我们可以通过在应用程序中配置模板路径,然后在视图函数中使用render_template
函数来渲染模板,将动态数据和静态内容结合起来,最终生成一个完整的HTML页面。
2.1 入门案例
来看一个例子,演示如何在Flask应用中使用Jinja2模板引擎:
# app.py
from flask import Flask, render_template
app = Flask(__name__)
app.config['TEMPLATES_AUTO_RELOAD'] = True # 设置模板自动重载
@app.route('/')
def index():
return render_template('index.html', name='John Doe')
我们在Flask应用的根目录下创建一个templates
文件夹,并在该文件夹下创建一个名为 index.html
的模板文件。在该模板文件中,我们可以使用Jinja2提供的语法来渲染动态数据和静态内容。
以下是一个简单的 index.html
模板文件的示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{ name }} - My Flask App</title>
</head>
<body>
<h1>Hello, {{ name }}!</h1>
</body>
</html>
{{ name }}
:表示要渲染的动态数据,其中name
是我们在视图函数中传递给模板的参数。
最后,我们可以通过访问 http://localhost:5000/
来查看渲染后的页面效果,页面将会显示 Hello, John Doe!
。
注意:
app.config['TEMPLATES_AUTO_RELOAD'] = True
是 Flask 应用中配置模板自动重载的参数。如果将其设置为 True,则在修改模板文件后,Flask 会自动重载模板,从而使得修改后的模板能够生效。这在开发阶段非常有用,因为可以避免每次修改模板后都需要手动重启应用的麻烦。
csdn链接:http://t.csdn.cn/ENFfK
2.2 条件判断
<!-- 条件判断 -->
{% if condition %}
<p>条件为真</p>
{% elif other_condition %}
<p>其他条件为真</p>
{% else %}
<p>所有条件都为假</p>
{% endif %}
2.3 循环遍历
<!-- 循环遍历 -->
{% for item in items %}
<li>{{ item }}</li>
{% else %}
<!-- 当 for 循环没有遍历到任何一个元素时,执行 else 代码块中的内容 -->
<li>列表为空</li>
{% endfor %}
2.4 过滤器
过滤器可以用管道符|
链接到变量之后。
例如,我们有一个变量name
,我们可以使用capitalize
过滤器将它的第一个字母大写:
{{ name | capitalize }}
还可以使用多个过滤器,其中每个过滤器的输出作为下一个过滤器的输入,如下所示:
{{ name | lower | replace(" ", "_") }}
上面把变量name
中的所有字母都转换为小写,并将空格替换为下划线。
Jinja2中的常见过滤器包括:
safe
: 标记值为安全,将不进行转义capitalize
: 将字符串的第一个字符大写lower
: 将字符串转换为小写upper
: 将字符串转换为大写title
: 将字符串的每个单词的首字母大写trim
: 删除字符串开头和结尾的空白字符replace
: 将字符串中的某个子串替换为另一个字符串
2.5 宏
宏是 Jinja2 中可重用的代码块,可以在模板的任何地方调用。
通过使用 Jinja2 中的 {% macro %}
标签定义宏,然后可以在模板的任何地方调用它。例如:
{% macro hello(name) %}
<h1>Hello, {{ name }}!</h1>
{% endmacro %}
这个宏定义了一个 hello
的宏,它接受一个名为 name
的参数,并返回一个带有 name
的 h1
标签。假设该宏在一个名为 hello_macro.html
的模板文件。
接下来,我们在另一个模板文件中使用这个宏。内容如下:
{% import 'hello_macro.html' as macros %}
{{ macros.hello('World') }}
这个文件中首先使用了 import
指令将 hello_macro.html
中的宏导入,并定义了一个名为 macros
的命名空间来包含这个宏。然后,我们就可以在文件中使用这个宏了。
最终生成的 HTML 代码将是:
<h1>Hello, World!</h1>
如果是在同一文件调用:
{{ hello('World') }}
下面是一个相对复杂的例子:
{% macro render_person(person) %}
<div class="person">
<h2>{{ person.name }}</h2>
<p>Age: {{ person.age }}</p>
{% if person.email %}
<p>Email: {{ person.email }}</p>
{% endif %}
</div>
{% endmacro %}
{% for person in people %}
{{ render_person(person) }}
{% endfor %}
- 在上面的例子中,我们定义了一个名为
render_person
的宏,用于渲染一个人的信息。 - 它接受一个
person
对象作为参数,并使用该对象的属性来渲染 HTML。 - 在主模板中,我们使用
for
循环来遍历人的列表,并使用render_person
宏来渲染每个人的信息。
2.6 定义临时变量
<!-- with定义临时变量 -->
{% with title="Hello, World!" %}
<h1>{{ title }}</h1>
{% endwith %}
{% with total = 1 + 2 %}
<!-- total=3 -->
{{ total }}
{% endwith %}
使用with
定义的变量作用范围在{% with %}
和{% endwith %}
之间。
还可以使用set
定义临时变量:
{% set x = 1 %}
{% if x %}
{% set y = 2 %}
{% endif %}
{{ x }} # 输出 1
{{ y }} # 报错,y未定义
set
的作用范围是定义它的块级范围,块级范围内的变量名只在该块级范围内有效,出了这个范围,这个变量名就失效了。
在这个例子中,{% set x = 1 %}
定义了变量 x
,作用范围为整个模板。在 if
语句中,当 x
的值为真时,{% set y = 2 %}
定义了变量 y
,作用范围为 if
语句块级范围。因此,当 if
语句的条件为假时,变量 y
未被定义,因此输出时会报错。
宏和临时变量:
- 宏是一段重复使用的代码块,它可以在模板中定义并在需要的地方调用。而临时变量则是在模板中定义的一个变量,它可以用来存储临时数据,并在模板中使用。
- 宏和临时变量的区别在于它们的作用范围和生命周期不同。宏是一段代码块,它的作用范围只在它所定义的模板中,它的生命周期是整个应用程序的生命周期。而临时变量的作用范围只在当前的上下文中,它的生命周期只是当前请求处理过程中。
2.7 定义模板
在 Flask 中,可以通过定义基础模板和扩展模板来实现代码的复用和管理,使得代码更加简洁和易于维护。
定义基础模板可以使用 {% block %}
和 {% endblock %}
标签,其中 {% block %}
定义了一个块,其内容可以被子模板继承和覆盖。
在子模板中可以使用 {% extends %}
标签继承基础模板,同时通过 {% block %}
标签覆盖父模板中定义的块。
举个例子,假设我们有一个父模板 base.html
,它包含了一个名为 content
的块。现在我们想要创建一个子模板 child.html
,它继承自父模板并重写 content
块,可以这样实现:
<!-- base.html -->
<!doctype html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
<!-- child.html -->
{% extends "base.html" %}
{% block title %}Child Template{% endblock %}
{% block content %}
<h1>Hello, World!</h1>
{% endblock %}
在子模板中:
- 我们使用
{% extends "base.html" %}
声明了它继承自base.html
- 使用
{% block ... %} ... {% endblock %}
块声明了要重写的内容。 - 这样,
child.html
就拥有了base.html
中的所有内容,并且可以根据自己的需求覆盖base.html
中的块内容。 - 当子模板被渲染时,Jinja2 会先加载父模板
base.html
,然后替换其中的content
块为子模板child.html
中定义的内容。
3. Flask-WTF表单处理和验证
- 在 Flask 中,表单处理和验证一般使用 Flask-WTF 插件实现。
- Flask-WTF 是 Flask 的一个扩展,它集成了 WTForms,是一个流行的 Python 表单处理库。使用 Flask-WTF 可以方便地创建表单,并对表单数据进行验证和处理。
- 在 Flask-WTF 中,表单通常是通过定义一个继承自
FlaskForm
类的类来实现的。这个类中定义了表单中各个字段的类型、标签、验证规则等信息。 - 使用 Flask-WTF 中的
form
对象可以在模板中生成表单,并通过validate_on_submit()
方法对表单数据进行验证和处理。
3.1 安装 Flask-WTF
pip install Flask-WTF
3.2 定义表单类
在 Flask 中定义表单类可以使用 Flask-WTF 扩展中的 FlaskForm
类,也可以使用 WTForms 库中的 Form
类。后面主要以使用 FlaskForm
为例。
每个表单字段都是一个实例变量,可以设置不同的参数,如字段类型、标签、验证规则等。
例如,如果需要使用字符串类型字段和数据验证器,可以这样定义表单类:
from flask_wtf import FlaskForm
from wtforms import StringField, validators
class MyForm(FlaskForm):
name = StringField('Name', validators=[validators.DataRequired()])
在上面的代码中,定义了一个名为 MyForm
的表单类,其中包含一个字符串类型的 name
字段,该字段使用了 DataRequired
验证器,用于验证该字段的值是否为空。
3.2.1 字段类型和验证器
常用的字段类型:
字段类型 | 描述 |
---|---|
StringField | 字符串字段,用于接受字符串类型的数据 |
IntegerField | 整型字段,用于接受整数类型的数据 |
DecimalField | 十进制浮点型字段,用于接受浮点型数据,可以指定精度 |
BooleanField | 布尔型字段,用于接受 True 或 False 类型的数据 |
DateField | 日期型字段,用于接受日期类型的数据 |
TimeField | 时间型字段,用于接受时间类型的数据 |
DateTimeField | 日期时间型字段,用于接受日期时间类型的数据 |
FileField | 文件上传字段,用于接受上传文件类型的数据 |
RadioField | 单选按钮字段 |
CheckboxField | 复选框字段 |
验证器:
DataRequired | 确保字段不为空 | message |
---|---|---|
EqualTo | 比较两个字段的值是否相等 | message, fieldname |
Length | 确保字段值的长度在给定范围内 | message, min, max |
确保字段值是合法的电子邮件地址 | message | |
URL | 确保字段值是合法的 URL 地址 | message |
NumberRange | 确保字段值在数字范围内 | message, min, max |
Regexp | 使用正则表达式验证字段值 | message, regex |
Optional | 使字段变为可选项 | 无 |
参数message表示自定义错误提示信息。如果参数未指定,则使用默认的错误提示信息。
3.2.2 综合案例
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, Email, EqualTo
class RegistrationForm(FlaskForm):
"""
注册表单类
"""
username = StringField('Username', validators=[DataRequired(), Length(min=2, max=20)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Sign Up')
这个表单类定义了一个用户注册表单,包含用户名、电子邮件、密码和确认密码等字段。
其中,StringField
表示字符串类型的字段,PasswordField
表示密码类型的字段,SubmitField
表示提交按钮类型的字段。
验证器中,DataRequired
表示该字段必须填写,Length
表示该字段长度限制,Email
表示该字段必须是电子邮件格式,EqualTo
表示该字段必须与另一个字段相等。
最后,submit
表示提交按钮。
3.3 渲染表单
视图函数中,可以通过创建一个表单对象来渲染表单,并将其传递给模板进行渲染。
在模板中,可以使用 form.<field_name>
来渲染表单字段。
下面是一个简单的视图函数的示例:
from flask import render_template
from app import app
from forms import LoginForm
@app.route('/login')
def login():
form = LoginForm()
return render_template('login.html', form=form)
3.4 处理表单提交
处理表单提交时的一般流程如下:
- 用户在浏览器端填写表单并点击“提交”按钮,浏览器向服务器发送POST请求;
- Flask应用接收到请求,解析请求体中的表单数据,生成一个
request
对象; - Flask应用根据请求的URL和请求方法选择对应的视图函数进行处理;
- 视图函数从
request
对象中获取表单数据,对数据进行验证和处理; - 如果表单数据验证通过,视图函数进行相应的业务逻辑处理;
- 如果表单数据验证不通过,视图函数返回一个带有错误信息的响应,通常是重新渲染表单页面,并在页面中显示相应的错误信息;
- 视图函数根据业务逻辑的处理结果,生成响应对象,并返回给客户端。
4. 数据库操作和SQLAlchemy
在Flask中,常用的数据库操作有两种方式:
- 使用原生的SQL语句操作数据库。
- 使用ORM框架操作数据库,常用的ORM框架有SQLAlchemy。
下面我们主要介绍使用SQLAlchemy的方式。
SQLAlchemy是Python中最著名的ORM框架之一,它提供了高度封装的SQL操作方式,可以让我们使用Python语言来操作数据库,而不用编写复杂的SQL语句。
SQLAlchemy还提供了非常好的数据模型定义方式,可以大大减少我们编写数据库代码的工作量。
4.1 安装
pip install SQLAlchemy
4.2 配置数据库连接
安装完成后,我们需要在Flask应用中配置数据库连接,以便于在应用中使用。Flask中的数据库连接配置通常保存在app.config对象中。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://username:password@hostname/database_name'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
上面的代码中,我们定义了一个Flask应用,并使用SQLAlchemy连接到了一个MySQL数据库。
其中,'username’和’password’分别是数据库用户名和密码,'hostname’是数据库服务器地址,'database_name’是数据库名。
4.3 定义数据模型类
在Flask应用中,我们需要定义数据模型类,以便于ORM框架进行数据操作。
下面是一个简单的数据模型类的定义:
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def __repr__(self):
return '<User {}>'.format(self.name)
上面的代码中,我们定义了一个User数据模型类,它继承自db.Model类,这个类是SQLAlchemy提供的基类,用来定义数据模型类。
在User类中,我们定义了表名、字段名和字段类型等信息,这些信息会被SQLAlchemy自动映射到数据库中。
在__repr__方法中,我们定义了打印对象时的输出信息。
4.4 数据操作
定义好数据模型类之后,我们就可以使用ORM框架进行数据操作了。
ORM框架提供了各种各样的查询方法,例如查询所有数据、查询单个数据、过滤数据等。
下面是一些简单的查询方法的例子:
# 查询所有用户
users = User.query.all()
# 查询第一个用户
user = User.query.first()
# 根据id查询用户
user = User.query.get(1)
# 过滤数据
users = User.query.filter_by(name='Alice').