如何在 Flask 应用程序中使用 Flask-SQLAlchemy 与数据库交互

作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。

介绍

在网络应用程序中,你通常需要一个数据库,这是一个有组织的数据收集。你使用数据库来存储和维护可有效地检索和操纵的持久数据。例如,在社交媒体应用程序中,你有一个数据库,其中用户数据(个人信息,帖子,评论,追随者)是以一种可以有效地操纵的方式存储的。你可以将数据添加到数据库,检索它,修改它或删除它,取决于不同的要求和条件。在网络应用程序中,这些要求可能是用户添加新帖子,删除帖子,或删除他们的帐户,这可能或可能不会删除他们的帖子。你执行的操作来操纵数据将取决于应用程序中的特定功能。例如,你可能不想让用户添加没有标题的帖子。

Flask 是一个轻量级的 Python 网页框架,为创建 Python 语言的 Web 应用程序提供了有用的工具和功能。 SQLAlchemy是一个 SQL 工具包,为关系数据库提供高效和高性能的数据库访问。 它提供了与诸如 SQLite、MySQL 和 PostgreSQL 等多个数据库引擎进行交互的方式。 它为您提供数据库的 SQL 功能。 它还为您提供了一个 Object Relational Mapper (ORM),允许您使用简单的 Python 对象和方法进行查询和处理数据。 Flask-SQLAlchemy是一个 Flask 扩展程序,使使用 SQLAlchemy 与 Flask 更容易,为您提供工具和方法来通过 SQLAlch

在本教程中,您将构建一个小型学生管理系统,展示如何使用Flask-SQLAlchemy扩展。您将与Flask一起使用它来执行基本任务,例如连接到数据库服务器,创建表,将数据添加到您的表,检索它,并从您的数据库中更新和删除项目。您将使用SQLAlchemy与SQLite(https://sqlite.org/index.html),尽管您也可以使用它与其他数据库引擎,如PostgreSQL和MySQL。SQLite与Python一起工作,因为Python标准库提供了 sqlite3模块,SQLAlchemy在幕后使用它来与SQLite数据库进行交互,而无需安装任何东西。SQlite在Linux系统上默认安装,并且作为Python包的一部分

前提条件

步骤 1 — 安装 Flask 和 Flask-SQLAlchemy

在此步骤中,您将为您的应用程序安装所需的包。

當您的虛擬環境啟用時,使用「pip」來安裝 Flask 和 Flask-SQLAlchemy:

1pip install Flask Flask-SQLAlchemy

一旦安装成功完成,您将在输出结束时看到一个类似于以下的行:

1[secondary_label Output]
2Successfully installed Flask-2.0.3 Flask-SQLAlchemy-2.5.1 Jinja2-3.0.3 MarkupSafe-2.1.0 SQLAlchemy-1.4.31 Werkzeug-2.0.3 click-8.0.4 greenlet-1.1.2 itsdangerous-2.1.0

安装所需的 Python 包后,您将下一步设置数据库。

步骤 2 – 设置数据库和模型

在此步骤中,您将设置数据库连接,并创建 SQLAlchemy database model,即代表存储数据的Python类。

创建数据库连接

在您的flask_app目录中打开名为app.py的文件. 此文件将包含设置数据库和您的Flask路径的代码:

1nano app.py

此檔案將連接到名為「database.db」的 SQLite 資料庫,並具有名為「學生」的類別,它代表您的資料庫學生表儲存學生資訊,除了您的 Flask 路線。

1[label flask_app/app.py]
2import os
3from flask import Flask, render_template, request, url_for, redirect
4from flask_sqlalchemy import SQLAlchemy
5
6from sqlalchemy.sql import func

在这里,您将导入 os 模块,它为您提供访问不同的操作系统界面,您将使用它来构建您的 `database.db' 数据库文件的文件路径。

flask包中,您可以导入应用程序所需的必要辅助工具:用于创建 Flask 应用程序实例的 Flask 类,用于渲染模板的 render_template() 函数,用于处理请求的 request 对象,用于构建路径 URL 的 url_for() 函数,以及用于重定向用户的 redirect() 函数。

然后,您从Flask-SQLAlchemy扩展中导入SQLAlchemy类,该类允许您访问 SQLAlchemy的所有函数和类,除了助手和集成Flask与SQLAlchemy的功能,您将使用它创建一个连接到Flask应用程序的数据库对象,允许您使用Python类、对象和功能创建和操纵表,而无需使用SQL语言。

您还可以从sqlalchemy.sql模块导入func辅助器,以访问 SQL 函数

在导入下方,您将设置数据库文件路径,实时化您的 Flask 应用程序,并配置和连接您的应用程序到 SQLAlchemy。

 1[label flask_app/app.py]
 2
 3basedir = os.path.abspath(os.path.dirname(__file__))
 4
 5app = Flask(__name__)
 6app.config['SQLALCHEMY_DATABASE_URI'] =\
 7        'sqlite:///' + os.path.join(basedir, 'database.db')
 8app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
 9
10db = SQLAlchemy(app)

在这里,您为您的 SQLite 数据库文件构建一条路径. 您首先将基础目录定义为当前目录. 您使用 os.path.abspath() 函数获取当前文件目录的绝对路径. 特殊的 __file__ 变量具有当前 app.py 文件的路径名称. 您将基础目录的绝对路径存储在一个名为 basedir 的变量中。

然后创建一个名为app的Flask应用程序实例,您可以使用它来配置两个Flask-SQLAlchemy 配置密钥:

  • SQLALCHEMY_DATABASE_URI: 数据库 URI 用于指定您想要建立连接的数据库。在这种情况下, URI 会按照格式 sqlite:///path/to/database.db 使用 os.path.join() 函数来智能地连接您在 basedir 变量中构建和存储的数据库目录,以及 database.db 文件名。 这将连接到您的 flask_app 目录中的 database.db 数据库文件。 该文件将在您启动数据库后创建。
  • SQL ALCHEMY_TRACK_MIFIFICATIONS: 一个配置允许或禁用对象的跟踪

<$>[注] 注:

如果您想使用 PostgreSQL 或 MySQL 等其他数据库引擎,则需要使用适当的 URI。

对于 PostgreSQL,使用以下格式:

1postgresql://username:password@host:port/database_name

对于思维:

1mysql://username:password@host:port/database_name

有关更多信息,请参阅 SQLAlchemy 引擎配置文档

通过设置数据库 URI 并禁用跟踪来配置 SQLAlchemy 后,您使用SQLAlchemy类创建数据库对象,通过应用程序实例将您的 Flask 应用程序连接到 SQLAlchemy。

宣布桌子

建立数据库连接和创建数据库对象后,您将使用数据库对象创建学生的数据库表,该表由 model 表示 - 一个继承从基础类的 Python 类 Flask-SQLAlchemy 通过您之前创建的 db 数据库实例提供。

 1[label flask_app/app.py]
 2# ...
 3
 4class Student(db.Model):
 5    id = db.Column(db.Integer, primary_key=True)
 6    firstname = db.Column(db.String(100), nullable=False)
 7    lastname = db.Column(db.String(100), nullable=False)
 8    email = db.Column(db.String(80), unique=True, nullable=False)
 9    age = db.Column(db.Integer)
10    created_at = db.Column(db.DateTime(timezone=True),
11                           server_default=func.now())
12    bio = db.Column(db.Text)
13
14    def __repr__(self):
15        return f'<Student {self.firstname}>'

在这里,您创建一个学生模型,该模型来自db.Model类,它代表学生表,您使用db.Column(https://docs.sqlalchemy.org/en/14/core/metadata.html#sqlalchemy.schema.Column)类来定义表的列。

您为学生模型定义了以下列:

  • 联合国 id': 学生身份证. 您定义它为 db 的整数 。 整数primary_key=True'将本列定义为:primary key,它将通过数据库为每个条目(即学生)指定一个独特的值.
  • 姓名 ' : 弟子名相从. 最大长度为 " 100 " 字符的字符串。 nullable=False'表示此列不应为空。
  • 上名' : 学生姓. 最大长度为 " 100 " 字符的字符串。 nullable=False'表示此列不应为空。
  • 电子邮件: 学生的电子邮件. 最大长度为 " 80 " 字符的字符串。 unique=True'表示每个电子邮件应为每个学生所独有。 nullable=False'表示此列不应为空。
  • 年龄: 学生年龄.
  • 创建_at: 在数据库中创建学生记录的时间. 您使用 ['db.DateTime' (https://docs.sqlalchemy.org/en/14/core/type_basics.html#sqlalchemy.types.DateTime]] 定义它为 Python ['datetime' (https://docs.python.org/3/library/datetime.html#datetime.datetime) 对象 。 timzone=True 允许时区支持 。 ['server_default' (https://docs.sqlalchemy.org/en/14/core/defaults.html#server-invoked-ddl-explicit-default-expressions])在创建表格时设置数据库中的默认值,这样默认值就由数据库而不是模型处理. 您将它通过 [func.now ()' (https://docs.sqlalchemy.org/en/14/core/functions.html#sqlalchemy.sql.functions.now) 函数,该函数称为 SQL now ()' 日期时函数。 在SQLite中,在创建学生桌时,它作为"CURRENT_TIMESTAMP"来渲染. *生物': 学生的生平。db.Text()'表示栏内有长文。 (英语)

请参阅 SQLAlchemy 文档 列类型,而不是您在上一个代码块中使用的类型。

特殊的 __repr__函数允许您给每个对象一个字符串表示,以便用于调试。

app.py文件现在将看起来如下:

 1[label flask_app/app.py]
 2import os
 3from flask import Flask, render_template, request, url_for, redirect
 4from flask_sqlalchemy import SQLAlchemy
 5
 6from sqlalchemy.sql import func
 7
 8basedir = os.path.abspath(os.path.dirname(__file__))
 9
10app = Flask(__name__)
11app.config['SQLALCHEMY_DATABASE_URI'] =\
12        'sqlite:///' + os.path.join(basedir, 'database.db')
13app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
14
15db = SQLAlchemy(app)
16
17class Student(db.Model):
18    id = db.Column(db.Integer, primary_key=True)
19    firstname = db.Column(db.String(100), nullable=False)
20    lastname = db.Column(db.String(100), nullable=False)
21    email = db.Column(db.String(80), unique=True, nullable=False)
22    age = db.Column(db.Integer)
23    created_at = db.Column(db.DateTime(timezone=True),
24                           server_default=func.now())
25    bio = db.Column(db.Text)
26
27    def __repr__(self):
28        return f'<Student {self.firstname}>'

保存并关闭app.py

创建数据库

现在您已设置数据库连接和学生模型,您将使用 Flask 壳创建基于学生模型的数据库和学生表。

當您的虛擬環境啟用時,請將「app.py」檔案設定為您的 Flask 應用程式,使用「FLASK_APP」環境變數。

1export FLASK_APP=app
2flask shell

将打开一个 Python 交互式壳,该特殊壳在您的 Flask 应用程序的背景下运行命令,以便您所呼叫的 Flask-SQLAlchemy 函数连接到您的应用程序。

导入数据库对象和学生模型,然后运行 db.create_all() 函数来创建与您的模型相关的表格. 在这种情况下,您只有一种模型,这意味着函数调用将在您的数据库中只创建一个表:

1from app import db, Student
2db.create_all()

让壳运行,打开另一个终端窗口,并导航到您的flask_app目录. 在flask_app中,您将看到一个名为database.db的新文件。

<$>[注] 注:

例如,如果您通过添加一个新列来修改您的模型,并运行db.create_all()函数,则您对该模型所做的更改不会应用到表中,如果该表已经存在于数据库中,解决方案是使用db.drop_all()函数删除所有现有的数据库表,然后用db.create_all()函数重现它们:

1db.drop_all()
2db.create_all()

这将适用于您对模型所做的更改,但还会删除数据库中的所有现有数据. 要更新数据库并保存现有数据,您需要使用 schema migration,允许您修改表并保存数据。

如果您收到错误,请确保数据库 URI 和模型声明正确。

人口桌子

创建数据库和学生表后,您将使用泡沫壳通过学生模型将一些学生添加到您的数据库中。

使用您之前打开的相同的闪存壳,或在您的flask_app目录中启用您的虚拟环境,打开一个新的:

1flask shell

若要将学生添加到您的数据库,您将导入数据库对象和学生模型,并创建学生模型的实例,通过以下关键字参数传递学生数据:

1from app import db, Student
2student_john = Student(firstname='john', lastname='doe',
3                       email='[email protected]', age=23,
4                       bio='Biology student')

student_john 对象代表一个将被添加到数据库的学生,但这个对象尚未写入数据库. 查看闪存壳中的对象以查看您用 `repr() 方法构建的表述字符串:

1student_john

您将收到以下输出:

1[secondary_label Output]
2<Student john>

您可以使用您在学生模型中定义的类属性来获取列的值:

1student_john.firstname
2student_john.bio
1[secondary_label Output]
2'john'
3'Biology student'

由于该学生尚未添加到数据库,其ID将为:

1print(student_john.id)
1[secondary_label Output]
2None

要将该学生添加到数据库中,您首先需要将其添加到管理数据库交易的 database session 中。Flask-SQLAlchemy 提供了 db.session 对象,您可以通过该对象来管理数据库的更改。

1db.session.add(student_john)

这会发出一个INSERT声明,但您不会收到一个ID,因为数据库交易尚未完成。

1db.session.commit()

现在学生 John 已被添加到数据库中,您可以获取其 ID:

1print(student_john.id)
1[secondary_label Output]
21

您也可以使用 db.session.add() 方法来编辑数据库中的项目,例如,您可以这样修改学生的电子邮件:

1student_john.email = '[email protected]'
2db.session.add(student_john)
3db.session.commit()

使用 Flask 壳将一些更多学生添加到您的数据库:

 1sammy = Student(firstname='Sammy',
 2               lastname='Shark',
 3               email='[email protected]',
 4               age=20,
 5               bio='Marine biology student')
 6
 7carl = Student(firstname='Carl',
 8               lastname='White',
 9               email='[email protected]',
10               age=22,
11               bio='Marine geology student')
12
13db.session.add(sammy)
14db.session.add(carl)
15db.session.commit()

现在,您可以使用查询属性查询学生表中的所有记录,使用all()方法:

1Student.query.all()

您将收到以下输出:

1[secondary_label Output]
2[<Student john>, <Student Sammy>, <Student Carl>]

在此时,您的数据库中有三名学生,接下来,您将为索引页面创建一个Flask路线,并在该页面上显示数据库中的所有学生。

步骤 3 – 显示所有记录

在此步骤中,您将创建路线和模板,以在索引页面上显示数据库中的所有学生。

让 Flask 壳运行,并打开新的终端窗口。

打开您的app.py文件,将索引页面的路线添加到它:

1nano app.py

添加下列路径到文件的末尾:

1[label flask_app/app.py]
2
3# ...
4
5@app.route('/')
6def index():
7    students = Student.query.all()
8    return render_template('index.html', students=students)

保存并关闭文件。

在这里,您使用app.route()装饰器创建一个index()视图函数. 在此函数中,您查询数据库,并将所有学生使用学生模型与查询属性,允许您使用不同的方法从数据库中获取一个或多个项目。 您使用all()方法获取数据库中的所有学生条目。 您将查询结果存储在名为学生的变量中,并将其传输到名为index.html的模板中,您使用render_template()辅助函数进行渲染。

在创建用于显示数据库中现有学生的index.html模板文件之前,您将首先创建一个基准模板,该模板将具有其他模板也将使用的所有基本HTML代码,以避免代码重复。

创建一个模板目录,然后打开一个名为base.html的新模板:

1mkdir templates
2nano templates/base.html

将以下代码添加到base.html文件中:

 1[label flask_app/templates/base.html]
 2<!DOCTYPE html>
 3<html lang="en">
 4<head>
 5    <meta charset="UTF-8">
 6    <title>{% block title %} {% endblock %} - FlaskApp</title>
 7    <style>
 8        .title {
 9            margin: 5px;
10        }
11
12        .content {
13            margin: 5px;
14            width: 100%;
15            display: flex;
16            flex-direction: row;
17            flex-wrap: wrap;
18        }
19
20        .student {
21            flex: 20%;
22            padding: 10px;
23            margin: 5px;
24            background-color: #f3f3f3;
25            inline-size: 100%;
26        }
27
28        .bio {
29            padding: 10px;
30            margin: 5px;
31            background-color: #ffffff;
32            color: #004835;
33        }
34
35        .name a {
36            color: #00a36f;
37            text-decoration: none;
38        }
39
40        nav a {
41            color: #d64161;
42            font-size: 3em;
43            margin-left: 50px;
44            text-decoration: none;
45        }
46    </style>
47</head>
48<body>
49    <nav>
50        <a href="{{ url_for('index') }}">FlaskApp</a>
51        <a href="#">Create</a>
52        <a href="#">About</a>
53    </nav>
54    <hr>
55    <div class="content">
56        {% block content %} {% endblock %}
57    </div>
58</body>
59</html>

保存并关闭文件。

此基础模板包含您在其他模板中需要重复使用的所有 HTML 锅炉板。标题块将被更换为为每个页面设置一个标题,而内容块将被替换为每个页面的内容。导航栏有三个链接:一个用于索引页面,该链接使用url_for()辅助函数链接到index()视图函数,一个用于Create**页面,一个用于About**页面,如果您选择将其添加到您的应用程序中。

接下来,打开一个新的 index.html 模板文件,这是你在 app.py 文件中提到的模板:

1nano templates/index.html

添加以下代码:

 1[label flask_app/templates/index.html]
 2{% extends 'base.html' %}
 3
 4{% block content %}
 5    <h1 class="title">{% block title %} Students {% endblock %}</h1>
 6    <div class="content">
 7        {% for student in students %}
 8            <div class="student">
 9                <p><b>#{{ student.id }}</b></p>
10                <b>
11                    <p class="name">{{ student.firstname }} {{ student.lastname }}</p>
12                </b>
13                <p>{{ student.email }}</p>
14                <p>{{ student.age }} years old.</p>
15                <p>Joined: {{ student.created_at }}</p>
16                <div class="bio">
17                    <h4>Bio</h4>
18                    <p>{{ student.bio }}</p>
19                </div>
20            </div>
21        {% endfor %}
22    </div>
23{% endblock %}

保存并关闭文件。

在这里,您将基础模板扩展并替换内容块的内容。您使用一个<h1>标题,它也作为一个标题。您在行{% for student in %}中使用一个 Jinja for loop来浏览每个学生的学生变量,您将从index()视图函数转移到这个模板。您显示学生ID,他们的姓名和姓名,电子邮件,年龄,他们被添加到数据库的日期,以及他们的生物。

在您的flask_app目录中启用虚拟环境时,请使用FLASK_APP环境变量告诉Flask关于该应用程序(在这种情况下是app.py) 然后将FLASK_ENV环境变量设置为development,以便在开发模式下运行应用程序并获取调试器的访问。有关Flask调试器的更多信息,请参阅如何处理Flask应用程序中的错误(LINK0)。

1export FLASK_APP=app
2export FLASK_ENV=development

接下来,运行应用程序:

1flask run

当开发服务器运行时,请使用您的浏览器访问以下URL:

1http://127.0.0.1:5000/

您将看到您添加到数据库的学生在一个类似于以下的页面:

Index Page

您已经在索引页面上显示了数据库中的学生,接下来,您将为学生页面创建路线,在那里您可以显示每个学生的详细信息。

步骤 4 – 显示单个记录

在此步骤中,您将使用 Flask 壳来查询学生的 ID,并创建一条路线和模板,以在专用页面上显示每个学生的详细信息。

在此步骤结束时,URL http://127.0.0.1:5000/1将是一个显示第一个学生的页面(因为它具有ID 1)。

让开发服务器运行,并打开一个新的终端窗口。

打开 Flask 壳,展示如何查询学生:

1flask shell

要查询记录并从数据库中获取数据,Flask-SQLAlchemy为模型类提供一个查询属性,您可以使用其方法以使用特定的过滤器获取记录。

例如,您可以使用 filter_by() 方法使用一个参数,例如 firstname,该参数匹配表中的一个列和一个参数,以获取特定学生:

1from app import db, Student
2Student.query.filter_by(firstname='Sammy').all()
1[secondary_label Output]
2[<Student Sammy>]

在这里,您可以获取所有学生的姓名为Sammy。 您可以使用all()方法获取所有结果的列表。 要获取第一个结果,这是这里唯一的结果,您可以使用first()方法:

1Student.query.filter_by(firstname='Sammy').first()
1[secondary_label Output]
2<Student Sammy>

要通过其ID获取学生,您可以使用 filter_by(id=ID):

1Student.query.filter_by(id=3).first()

或者,您可以使用更短的 get() 方法,它允许您使用其主要密钥获取特定项目:

1Student.query.get(3)

两者都将产生相同的结果:

1[secondary_label Output]
2<Student Carl>

你现在可以离开壳:

1exit()

要通过他们的ID获取一个学生,你将创建一个新的路径,为每个单独的学生渲染一个页面。你将使用Flask-SQLAlchemy提供的 get_or_404() 方法,这是 get() 方法的变体。 区别在于 get() 返回值 None 当没有结果匹配给定的 ID,而 get_or_404() 返回了 404 Not Found HTTP 响应。

1nano app.py

添加下列路径到文件的末尾:

1[label flask_app/app.py]
2# ...
3
4@app.route('/<int:student_id>/')
5def student(student_id):
6    student = Student.query.get_or_404(student_id)
7    return render_template('student.html', student=student)

保存并关闭文件。

在这里,您使用路线 '/<int:student_id>/',而 int: 是一个 转换器将 URL 中的默认字符串转换为整数,而 student_id 是决定您在页面上显示的学生的 URL 变量。

该ID通过student_id参数从 URL 传输到student()视图函数。在该函数内,您可以查询学生集合并使用get_or_404()方法检索学生的ID。

您将渲染一个名为student.html的模板,并将其传递给您获取的学生。

打开这个新的 student.html 模板文件:

1nano templates/student.html

在这个新的student.html文件中输入以下代码,它将类似于index.html模板,但只显示一个学生:

 1[label flask_app/templates/student.html]
 2{% extends 'base.html' %}
 3
 4{% block content %}
 5    <span class="title">
 6        <h1>{% block title %} {{ student.firstname }} {{ student.lastname }}{% endblock %}</h1>
 7    </span>
 8    <div class="content">
 9            <div class="student">
10                <p><b>#{{ student.id }}</b></p>
11                <b>
12                    <p class="name">{{ student.firstname }} {{ student.lastname }}</p>
13                </b>
14                <p>{{ student.email }}</p>
15                <p>{{ student.age }} years old.</p>
16                <p>Joined: {{ student.created_at }}</p>
17                <div class="bio">
18                    <h4>Bio</h4>
19                    <p>{{ student.bio }}</p>
20                </div>
21            </div>
22    </div>
23{% endblock %}

保存并关闭文件。

在此文件中,您将扩展基础模板,将学生的全名设置为页面的标题. 您将显示学生ID、学生的姓名和姓名、电子邮件、年龄、记录创建日期和他们的生物。

使用您的浏览器导航到第二名学生的URL:

1http://127.0.0.1:5000/2

你会看到一个类似于以下的页面:

Single Student Page

现在,编辑index.html,让每个学生的名字链接到他们的页面:

1nano templates/index.html

编辑for循环以显示如下:

 1[label flask_app/templates/index.html]
 2{% for student in students %}
 3    <div class="student">
 4        <p><b>#{{ student.id }}</b></p>
 5        <b>
 6            <p class="name">
 7                <a href="{{ url_for('student', student_id=student.id)}}">
 8                    {{ student.firstname }} {{ student.lastname }}
 9                </a>
10            </p>
11        </b>
12        <p>{{ student.email }}</p>
13        <p>{{ student.age }} years old.</p>
14        <p>Joined: {{ student.created_at }}</p>
15        <div class="bio">
16            <h4>Bio</h4>
17            <p>{{ student.bio }}</p>
18        </div>
19    </div>
20{% endfor %}

保存并关闭文件。

您已将<a>标签添加到学生的全名中,该标签使用url_for()函数链接到学生页面,将存储在student.id中的学生ID传输到student()视图函数中。

导航到您的索引页面或更新它:

1http://127.0.0.1:5000/

现在你会看到每个学生的名字链接到适当的学生页面。

创建单个学生的页面后,您将添加一个页面,将新学生添加到数据库中。

步骤五:创建新纪录

在此步骤中,您将为您的应用程序添加新的路线,以使用 Web 表单将新学生添加到数据库中。

然后,您将处理表单提交,使用学生模型为新学生创建对象,将其添加到会话中,然后执行交易,类似于您在步骤 2 中添加学生条目的方式。

让开发服务器运行,并打开一个新的终端窗口。

首先,打开app.py文件:

1nano app.py

app.py文件的末尾添加以下路线:

1[label flask_app/app.py]
2# ...
3
4@app.route('/create/', methods=('GET', 'POST'))
5def create():
6    return render_template('create.html')

保存并关闭文件。

在此路径中,您将‘GET’,‘POST’字符串传输到‘methods’参数,以允许 GET 和 POST 请求。 GET 请求用于从服务器中获取数据。 POST 请求用于将数据发送到特定路径。默认情况下,仅允许 GET 请求。当用户使用 GET 请求首次请求‘/create’ 路径时,将生成一个名为 ‘create.html’ 的模板文件。

打开新的create.html模板:

1nano templates/create.html

添加以下代码:

 1{% extends 'base.html' %}
 2
 3{% block content %}
 4    <h1 style="width: 100%">{% block title %} Add a New Student {% endblock %}</h1>
 5    <form method="post">
 6        <p>
 7            <label for="firstname">First Name</label>
 8            <input type="text" name="firstname"
 9                   placeholder="First name">
10            </input>
11        </p>
12
13        <p>
14            <label for="lastname">Last Name</label>
15            <input type="text" name="lastname"
16                   placeholder="Last name">
17            </input>
18        </p>
19
20        <p>
21            <label for="email">Email</label>
22            <input type="email" name="email"
23                   placeholder="Student email">
24            </input>
25        </p>
26
27        <p>
28            <label for="age">Age</label>
29            <input type="number" name="age"
30                   placeholder="Age">
31            </input>
32        </p>
33
34        <p>
35        <label for="bio">Bio</label>
36        <br>
37        <textarea name="bio"
38                  placeholder="Bio"
39                  rows="15"
40                  cols="60"
41                  ></textarea>
42        </p>
43        <p>
44            <button type="submit">Submit</button>
45        </p>
46    </form>
47{% endblock %}

保存并关闭文件。

您可以扩展基础模板,将标题设置为标题,并使用<form>标签,属性方法设置为发布,以表示表单将提交 POST 请求。

您有两个文本字段,名称为姓氏姓氏。您将使用这些名称访问用户在视图函数中提交的表单数据。

您有一个电子邮件字段,名称为电子邮件,学生年龄的号码字段和学生生物的文本区域。

最后,您在表单的末尾有一个提交按钮。

现在,随着开发服务器运行,使用您的浏览器导航到‘/create’路径:

1http://127.0.0.1:5000/create

您将看到一个 添加新学生页面,有一个网页表格和一个 提交按钮,如下:

Add a New Student

如果您填写表单并提交它,将 POST 请求发送到服务器,则不会发生任何事情,因为您没有在/create路径上处理 POST 请求。

打开 app.py 来处理用户提交的 POST 请求:

1nano app.py

编辑/create路径以显示如下:

 1[label flask_app/app.py]
 2
 3@app.route('/create/', methods=('GET', 'POST'))
 4def create():
 5    if request.method == 'POST':
 6        firstname = request.form['firstname']
 7        lastname = request.form['lastname']
 8        email = request.form['email']
 9        age = int(request.form['age'])
10        bio = request.form['bio']
11        student = Student(firstname=firstname,
12                          lastname=lastname,
13                          email=email,
14                          age=age,
15                          bio=bio)
16        db.session.add(student)
17        db.session.commit()
18
19        return redirect(url_for('index'))
20
21    return render_template('create.html')

保存并关闭文件。

您处理if request.method ==POST条件内的 POST 请求,您提取用户从request.form对象中提交的姓名、姓名、电子邮件、年龄和生物学,您将作为字符串传输的年龄转换为使用 [int()](https://docs.python.org/3.8/library/functions.html#int) Python 函数的整数,您使用学生模型构建一个学生`对象,您将学生对象添加到数据库会话中,然后进行交易。

最后,您将用户重定向到索引页面,在那里他们可以看到现有学生下面新添加的学生。

当开发服务器运行时,使用您的浏览器导航到‘/create’路径:

1http://127.0.0.1:5000/create

用一些数据填写表格并提交它。

您将被重定向到索引页面,您将看到新添加的学生。

现在你有添加新学生的功能,你需要在导航栏中添加一个链接到 Create页面。

1nano templates/base.html

通过修改创建链接的href属性值来编辑<body>标签:

 1[label flask_app/templates/base.html]
 2<body>
 3    <nav>
 4        <a href="{{ url_for('index') }}">FlaskApp</a>
 5        <a href="{{ url_for('create') }}">Create</a>
 6        <a href="#">About</a>
 7    </nav>
 8    <hr>
 9    <div class="content">
10        {% block content %} {% endblock %}
11    </div>
12</body>

保存并关闭文件。

更新您的索引页面,您将注意到导航栏中的 ** 创建** 链接现在功能。

现在你有一个网页表格添加新学生. 有关网页表格的更多信息,请参阅 如何在Flask应用程序中使用网页表格. 有关管理网页表格的更先进和更安全的方法,请参阅 如何使用和验证网页表格使用Flask-WTF

步骤 6 - 编辑记录

在此步骤中,您将为您的应用程序添加一个新页面以编辑现有学生数据. 您将添加一个新的 /ID/edit/ 路线以根据他们的 ID 编辑学生的数据。

打开app.py:

1nano app.py

将下列路线添加到文件的末尾. 这将捕获您想要使用其ID编辑的学生条目. 它将通过您以后创建的网页表格提交的新学生数据提取。

 1[label flask_app/app.py]
 2# ...
 3
 4@app.route('/<int:student_id>/edit/', methods=('GET', 'POST'))
 5def edit(student_id):
 6    student = Student.query.get_or_404(student_id)
 7
 8    if request.method == 'POST':
 9        firstname = request.form['firstname']
10        lastname = request.form['lastname']
11        email = request.form['email']
12        age = int(request.form['age'])
13        bio = request.form['bio']
14
15        student.firstname = firstname
16        student.lastname = lastname
17        student.email = email
18        student.age = age
19        student.bio = bio
20
21        db.session.add(student)
22        db.session.commit()
23
24        return redirect(url_for('index'))
25
26    return render_template('edit.html', student=student)

保存并关闭文件。

在这里,您有路线 /<int:student_id>/edit/ 它接受POST和GET方法,而 student_id’ 作为 URL 变量将 ID 传输到 edit() 视图函数。

学生模型上,您可以使用get_or_404()查询方法来获取与所述学生ID相关联的学生,这将以404 Not Found错误响应,如果数据库中没有具有所述学生ID的学生。

如果该请求是 GET 请求,这意味着用户没有提交表单,那么这个条件是假的,并且里面的代码将被跳过到行 return render_template('edit.html', student=student). 这将使一个 edit.html 模板,通过它从数据库中获得的学生对象,允许您用当前的学生数据填写学生网页表单。

当用户编辑学生数据并提交表单时,在if request.method ==POST中执行代码。您将从request.form`对象中提交的学生数据提取到相应的变量。

将学生数据设置为新提交的数据后,您将学生对象添加到数据库会话中,然后进行更改,最后将用户重定向到索引页面。

接下来,您需要创建一个页面,用户可以进行编辑。

1nano templates/edit.html

这个新文件将有一个类似于在create.html文件中的网页表格,其中当前的学生数据作为字段的默认值。

 1[label flask_app/templates/edit.html]
 2
 3{% extends 'base.html' %}
 4
 5{% block content %}
 6    <h1 style="width: 100%">
 7        {% block title %} Edit {{ student.firstname }}
 8                               {{ student.lastname }}'s Details
 9        {% endblock %}
10    </h1>
11    <form method="post">
12        <p>
13            <label for="firstname">First Name</label>
14            <input type="text" name="firstname"
15                   value={{ student.firstname }}
16                   placeholder="First name">
17            </input>
18        </p>
19
20        <p>
21            <label for="lastname">Last Name</label>
22            <input type="text" name="lastname"
23                   value={{ student.lastname }}
24                   placeholder="Last name">
25            </input>
26        </p>
27
28        <p>
29            <label for="email">Email</label>
30            <input type="email" name="email"
31                   value={{ student.email }}
32                   placeholder="Student email">
33            </input>
34        </p>
35
36        <p>
37            <label for="age">Age</label>
38            <input type="number" name="age"
39                   value={{ student.age }}
40                   placeholder="Age">
41            </input>
42        </p>
43
44        <p>
45        <label for="bio">Bio</label>
46        <br>
47        <textarea name="bio"
48                  placeholder="Bio"
49                  rows="15"
50                  cols="60"
51                  >{{ student.bio }}</textarea>
52        </p>
53        <p>
54            <button type="submit">Submit</button>
55        </p>
56    </form>
57{% endblock %}

保存并关闭文件。

每个输入字段的属性和生物文本区域的值被设置为您从edit()视图函数转移到edit.html模板的学生对象中的相应值。

现在,导航到下面的 URL 来编辑第一个学生的详细信息:

1http://127.0.0.1:5000/1/edit

你会看到一个类似于以下的页面:

Edit a Student

编辑学生的数据并提交表单,您将被重定向到索引页面,学生的信息将被更新。

接下来,您将在索引页面上的每个学生下面添加一个 ** 编辑 ** 按钮,链接到他们的编辑页面。

1nano templates/index.html

在这个 index.html 文件中编辑for循环,看起来完全如下:

 1[label flask_app/templates/index.html]
 2
 3{% for student in students %}
 4    <div class="student">
 5        <p><b>#{{ student.id }}</b></p>
 6        <b>
 7            <p class="name">
 8                <a href="{{ url_for('student', student_id=student.id)}}">
 9                    {{ student.firstname }} {{ student.lastname }}
10                </a>
11            </p>
12        </b>
13        <p>{{ student.email }}</p>
14        <p>{{ student.age }} years old.</p>
15        <p>Joined: {{ student.created_at }}</p>
16        <div class="bio">
17            <h4>Bio</h4>
18            <p>{{ student.bio }}</p>
19        </div>
20        <a href="{{ url_for('edit', student_id=student.id) }}">Edit</a>
21    </div>
22{% endfor %}

保存并关闭文件。

在这里,您添加一个<a>标签,链接到edit()视图函数,通过student.id值链接到每个学生的编辑页面,并链接到Edit**

您现在有一个页面来编辑现有学生,接下来,您将添加一个删除按钮,以从数据库中删除学生。

步骤 7 – 删除记录

在此步骤中,您将添加一个新的路线和 Delete按钮来删除现有学生。

您的新删除()视图函数将收到您想要删除的学生的ID,将该ID传输到学生模型上的get_or_404()查询方法,以获取它,如果它存在,或者在数据库中没有找到该ID的学生时,用404 Not Found页面回复。

打开app.py来编辑:

1nano app.py

将下列路径添加到文件的末尾:

 1[label flask_app/app.py]
 2
 3# ...
 4
 5@app.post('/<int:student_id>/delete/')
 6def delete(student_id):
 7    student = Student.query.get_or_404(student_id)
 8    db.session.delete(student)
 9    db.session.commit()
10    return redirect(url_for('index'))

保存并关闭文件。

在这里,您使用了 Flask 版本 2.0.0中引入的 app.post]装饰器,而不是使用常见的 app.route 装饰器。例如, @app.post("/login")@app.route("/login", methods=["POST"]) 的缩略。这意味着此视图功能只接受 POST 请求,而浏览器上的 /ID/delete 路线将返回一个 405 方法不允许 错误,因为 Web 浏览器默认为 GET 请求。

删除()视图函数通过student_id URL 变量获取学生的ID,您使用get_or_404()方法获取学生并将其保存到学生变量中,或者在学生不存在的情况下用404 Not Found响应。您使用数据库会话中的删除()方法在db.session.delete(student)行中,将其传递给学生对象。这将设置会话以在交易发生时删除学生。由于您不需要进行任何其他修改,您将直接使用db.session.commit()进行交易。最后,您将用户重定向到页面索引。

接下来,编辑index.html模板以添加一个删除学生按钮:

1nano templates/index.html

通过直接在 Edit链接下方添加一个新的 <form> 标签来编辑 for 循环:

 1[label flask_app/templates/index.html]
 2
 3{% for student in students %}
 4    <div class="student">
 5        <p><b>#{{ student.id }}</b></p>
 6        <b>
 7            <p class="name">
 8                <a href="{{ url_for('student', student_id=student.id)}}">
 9                    {{ student.firstname }} {{ student.lastname }}
10                </a>
11            </p>
12        </b>
13        <p>{{ student.email }}</p>
14        <p>{{ student.age }} years old.</p>
15        <p>Joined: {{ student.created_at }}</p>
16        <div class="bio">
17            <h4>Bio</h4>
18            <p>{{ student.bio }}</p>
19        </div>
20        <a href="{{ url_for('edit', student_id=student.id) }}">Edit</a>
21
22        <hr>
23        <form method="POST"
24                action="{{ url_for('delete', student_id=student.id) }}">
25            <input type="submit" value="Delete Student"
26                onclick="return confirm('Are you sure you want to delete this entry?')">
27        </form>
28
29    </div>
30{% endfor %}

保存并关闭文件。

在这里,您有一个网页表格,将POST请求提交到删除()视图函数中。您将student.id作为student_id参数的参数,以指定要删除的学生条目。

更新您的索引页面。

每个学生的入口下面会看到一个删除学生按钮. 点击它并确认删除,您将被重定向到索引页面,学生将不再存在。

现在您可以从您的学生管理应用程序中删除学生的数据库。

结论

您建立了一个小型的 Flask Web 应用程序来管理学生使用 Flask 和 Flask-SQLAlchemy 使用 SQLite 数据库. 您学会了如何连接到您的数据库,设置代表您的表的数据库模型,将项目添加到您的数据库,查询您的表,并修改数据库数据。

使用 SQLAlchemy 在您的应用程序中允许您使用 Python 类和对象来管理您的 SQL 数据库. 而不是 SQLite,您可以使用另一个数据库引擎,并且除了负责连接的 SQLALCHEMY_DATABASE_URI 配置之外,您不需要更改核心应用程序代码中的任何东西。

如果您想了解更多关于 Flask 的信息,请参阅 如何使用 Flask 构建 Web 应用程序系列的其他教程。

Published At
Categories with 技术
comments powered by Disqus