Python Flask 和数据库系统交互
- Python Flask 和数据库系统交互
Python Flask 和数据库系统交互
全栈网页应用程序需要结构化数据的持久性,因此使用数据库的知识和经验是网页开发的先决条件。Python 和Flask 可以与大多数SQL或无SQL数据库系统集成。Python本身附带了一个名为sqlite3的轻量级SQLite数据库。我们将使用SQLite,因为它不需要设置单独的数据库服务器,并且非常适合小规模应用程序。对于生产环境,我们必须使用其他数据库系统,如MySQL、MariaDB或PostgreSQL。为了访问数据库系统并与之交互,我们将使用Flask扩展之一FlaskSQLAlchemy。Flask-SQLAlchemy扩展基于Python的SQLAlchemy库,使该库可用于我们的网页应用程序。SQLAlchemy库提供了一个对象关系映射器(ORM),这意味着它将我们的数据库表映射到Python对象。ORM库的使用不仅加快了开发周期,而且提供了在不更改代码的情况下切换底层数据库系统的灵活性。因此,我们建议使用 SQLAlchemy
或类似的库来处理数据库系统。
要从我们的应用程序与任何数据库系统交互,我们需要像往常一样创建Flask应用程序实例。下一步是使用数据库位置的URL(在SQLite3的情况下是一个文件)配置应用程序实例。创建应用程序实例后,我们将通过将其传递给应用程序实例来创建 SQLAlchemy
实例。使用 SQLite 等数据库时,我们只需在第一次初始化数据库。它可以从Python程序启动,但我们不赞成这种方法,以避免每次启动应用程序时都重置数据库。建议使用 SQLAlchemy
实例从命令行初始化数据库一次。在代码示例之后,我们将讨论初始化数据库的确切步骤。
为了说明SQLAlchemy库在我们的网页应用程序中的使用,我们将创建一个简单的应用程序来添加、列出和删除数据库表中的学生对象。以下是应用程序的示例代码,用于初始化Flask应用程序和数据库实例(SQLAlchemy实例),以及创建 Student
类的 Model
对象:
# 与数据库交互第一部分:创建和删除列表对象
from flask import Flask, render_template, request, redirect
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///student.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), nullable=False)
grade = db.Column(db.String(20), nullable=True)
def __repr__(self):
return '<Student %r>' % self.name
一旦我们创建了 SQLAlchemy
实例 db
,我们就可以使用数据库对象。SQLAlchemy
等ORM库的美妙之处在于,我们可以在 Python 中将数据库模式定义为 Python 类,在 ORM 术语中称为模型。对于我们的代码示例,我们创建了一个类 Student
,它继承自基类 db.Model
。在这个模型类中,我们定义了 id
、name
和 grade
属性,这些属性将对应于 SQLite3
数据库实例中数据库表 Student
中的三列。对于每个属性,我们定义了它的数据类型,包括最大长度、是否有主键以及是否可以为空。这些额外的属性定义对于以优化的方式配置数据库表非常重要。
在下面的代码片段中,我们将演示一个Python函数 list_students
,用于从数据库中获取学生对象列表。此函数映射到示例网页应用程序的 /list
URL,它通过在查询实例上使用 all
方法(db
实例的一个属性)从数据库表返回所有 Student
对象。请注意,查询实例及其方法可以从基类 db.Model
中获得:
# 第二部分
@app.get('/list')
def list_students():
students_list = Student.query.all()
return render_template('app.html', students=students_list)
在下一个代码片段中,我们将编写一个函数(add_student
)将学生添加到数据库表中。此函数映射到 /add
URL,并期望使用 GET
方法将学生的姓名和成绩作为请求参数传递。要向数据库中添加新对象,我们将使用必要的属性值创建 Student
类的新实例,然后使用 db.Session
实例通过使用 add
函数添加到 ORM 层。add
函数本身不会将实例添加到数据库中。我们将使用 commit
方法将其推送到数据库表中。一旦一个新的学生被添加到我们的数据库表中,我们就会将控制重定向到/list
URL。我们使用重定向到此 URL 的原因是,我们想在添加新学生后返回最新的学生列表,并重用我们已经实现的 list_students
函数。add_student
函数的完整代码如下:
# 第三部分
@app.get('/add')
def add_student():
fname = request.args['fname'
lname = request.args.get('lname', '')
grade = request.args.get('grade', '')
student = Student(name=f"{fname} {lname}", grade=grade)
db.session.add(student)
db.session.commit()
return redirect('/list')
在这个代码示例的最后一部分,我们将编写一个 Python 函数(delete_student
)从数据库表中删除一个学生。此函数映射到/delete<int:id>
URL。请注意,我们希望客户端发送学生 id
(我们使用 /list
列表请求将其与学生列表一起发送)。要删除学生,首先,我们使用学生 ID 查询确切的学生实例。这是通过在查询实例上使用 filter_by
方法来实现的。一旦我们有了确切的 Student
实例,我们就使用 db.Session
的 delete
方法,然后提交更改。与 add_student
函数一样,我们将客户端重定向到 /list
URL,以向我们的Jinja
模板返回最新的学生列表:
# 第四部分
@app.get('/delete/<int:id>')
def delete_student(id):
todelete = Student.query.filter_by(id).first()
db.session.delete(todelete)
db.session.commit()
return redirect('/list')
为了在浏览器中显示学生列表,我们创建了一个简单的 Jinja 模板(app.html
)。app.html
模板文件将以表格形式提供学生列表。值得注意的是,我们使用 Jinja for
循环动态构建 HTML 表行,如下面的 Jinja 模板所示:
<!DOCTYPE html>
<body>
<h2>Students</h2>
{% if students|length > 0 %}
<table>
<thead>
<tr>
<th scope="col">SNo</th>
<th scope="col">name</th>
<th scope="col">grade</th>
</tr>
</thead>
<tbody>
{% for student in students %}
<tr>
<th scope="row">{{student.id}}</th>
<td>{{student.name}}</td>
<td>{{student.grade}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</body>
</html>
在启动此应用程序之前,我们应该一次性初始化数据库模式。这可以通过使用 Python 程序来实现,但我们必须确保代码只执行一次,或者只在数据库尚未初始化时执行。推荐的方法是使用 Python shell 手动执行此步骤。在 Python shell 中,我们可以从应用程序模块导入 db
实例,然后使用 db.create_all
方法根据程序中定义的模型类初始化数据库。以下是我们的应用程序用于数据库初始化的示例命令:
>>> from app5 import db
>>> db.create_all()
这些命令将在程序所在的同一目录中创建一个 student.db
文件。要重置数据库,我们可以删除 student.db
文件并重新运行初始化命令,也可以使用 Python shell 中的 db.drop_all
方法。
我们可以使用 curl 实用程序或通过浏览器使用以下 URL 测试应用程序:
http://localhost:5000/list
http://localhost:5000/add?fname=John&Lee=asif&grade=9
http://localhost:5000/delete/<id>
<完>