Flask应用的基本组成部分、模板引擎Jinja2的使用、Flask-WTF、SQLAlchemy

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提供的语法来渲染动态数据和静态内容。

image-20230226221318273

以下是一个简单的 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!
Alt

注意:

  • 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 的参数,并返回一个带有 nameh1 标签。假设该宏在一个名为 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
Email确保字段值是合法的电子邮件地址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 处理表单提交

处理表单提交时的一般流程如下:

  1. 用户在浏览器端填写表单并点击“提交”按钮,浏览器向服务器发送POST请求;
  2. Flask应用接收到请求,解析请求体中的表单数据,生成一个request对象;
  3. Flask应用根据请求的URL和请求方法选择对应的视图函数进行处理;
  4. 视图函数从request对象中获取表单数据,对数据进行验证和处理;
  5. 如果表单数据验证通过,视图函数进行相应的业务逻辑处理;
  6. 如果表单数据验证不通过,视图函数返回一个带有错误信息的响应,通常是重新渲染表单页面,并在页面中显示相应的错误信息;
  7. 视图函数根据业务逻辑的处理结果,生成响应对象,并返回给客户端。

4. 数据库操作和SQLAlchemy

在Flask中,常用的数据库操作有两种方式:

  1. 使用原生的SQL语句操作数据库。
  2. 使用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').
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

就是搞笑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值