作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。
介绍
在网络应用程序中,你通常需要一个数据库,这是一个有组织的数据收集。你使用数据库来存储和维护可有效地检索和操纵的持久数据。例如,在社交媒体应用程序中,你有一个数据库,其中用户数据(个人信息,帖子,评论,追随者)是以一种可以有效地操纵的方式存储的。你可以将数据添加到数据库,检索它,修改它或删除它,取决于不同的要求和条件。在网络应用程序中,这些要求可能是用户添加新帖子,删除帖子,或删除他们的帐户,这可能或可能不会删除他们的帖子。你执行的操作来操纵数据将取决于应用程序中的特定功能。例如,你可能不想让用户添加没有标题的帖子。
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包的一部分
前提条件
- 一个本地的Python 3编程环境. 在 How To Install and Set Up a Local Programming Environment for Python 3]系列中跟随您的分布的教程。 在本教程中,我们将称我们的项目目录为
flask_app
。 - 对基本的Flask概念的理解,如路径,视图函数和模板。 如果您不熟悉Flask,请参阅 How to Create First Your Web Application Using Flask and Python和 How to Use Templates in a Flask Application. 对基本的HTML概念的理解。您可以查看我们的 How To Build a Website with HTML教程
步骤 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/
您将看到您添加到数据库的学生在一个类似于以下的页面:
您已经在索引页面上显示了数据库中的学生,接下来,您将为学生页面创建路线,在那里您可以显示每个学生的详细信息。
步骤 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
你会看到一个类似于以下的页面:
现在,编辑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
您将看到一个 添加新学生页面,有一个网页表格和一个 提交按钮,如下:
如果您填写表单并提交它,将 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
你会看到一个类似于以下的页面:
编辑学生的数据并提交表单,您将被重定向到索引页面,学生的信息将被更新。
接下来,您将在索引页面上的每个学生下面添加一个 ** 编辑 ** 按钮,链接到他们的编辑页面。
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 应用程序系列的其他教程。