用SQLAlchemy整合Flask数据库
数据库是构建Web应用程序不可或缺的组成部分。在网络应用程序的整个生命周期中,用户会发送一些需要存储的数据,以供将来参考。同时,用户也要求从它们的存储地获得信息。
数据和信息是使网络应用程序有价值的方面。如果用户不能从你的网络应用程序发送或接收数据,那么它就不能提供使用价值。因此,由用户提供的信息必须存储在数据库中,以便以后可以访问。
在Flask Web应用程序中,为了操作数据库,我们可以使用SQL和对象关系映射(ORM)。ORM使程序员更容易编写SQL查询,因为它使我们能够用面向对象的语言编写查询,然后ORM自动将其翻译成SQL,并将结果作为一个对象进行检索。
前提条件
本文的先决条件包括对以下概念的理解。
- Flask网络应用的基本用法和实现。
- 了解Python的面向对象编程概念。
- 了解Flask的视图和模板。
- 使用终端的中级知识。
- 对数据库的基本了解。
设置工作环境
在我们使用SQLAlchemy库之前,我们需要运行一个Flask应用程序。为了使这个过程更简单,我们将克隆一个现有的Flask网络应用程序,该程序其中包含一个已经设置好所有路线的注册表。
我们继续从这个Github资源库克隆启动包文件。
$ git clone https://github.com/corpsgeek/flask-form-handling.git
将目录改为克隆的文件夹,用命令安装requirement.txt 文件中的包。
$ pip install -r requirement.txt
我们还需要将flask环境变量设置为开发,默认状态是生产环境。
$ export FLASK_ENV="DEVELOPMENT"
上面的终端命令将flask环境设置为开发环境。现在,我们可以使用以下命令运行我们的flask应用。
$ flask run
我们的flask网络应用应该是活的。重定向到主机URL(127.0.0.1:5000),你应该可以看到显示 "Hello world "的主页。导航到注册路线127.0.0.1:5000/register ,查看注册页面。
安装和设置SQLAlchemy
为了使用SQLAlchemy,我们需要先安装SQLAlchemy库。
$ pip install SQLAlchemy
安装了SQLAlchemy后,我们必须从flask_sqlalchemy 模块中导入SQLAlchemy类到我们项目的主应用程序文件(__init__.py)。
# import sqlaclhemy from the flask_sqlachemy module
from flask_sqlalchemy import SQLAlchemy
接下来,继续配置数据库文件的变量。在这种情况下,我们使用的是SQL数据库,因此我们利用SQLite来通过我们的数据库运行查询。
# set the database uniform resource identifier for the database
app.config["SQLALCHEMY_DATABASE_URI"] = 'sqlite:///registration.db'
在上面的代码中,SQLite统一资源指标将接收数据库的名称,在我们的例子中是registration.db 。有了这个设置,我们必须通过创建一个SQLAlchemy类的对象来初始化数据库连接,然后我们把我们的应用程序作为一个参数传递。
# create an instance of the database module
db = SQLAlchemy(app)
通过上述过程,我们已经初始化了我们的数据库并准备好工作。但我们不能向这个数据库添加数据,因为它不包含用于存储注册细节的表。
然而,为了解决这个问题,我们必须开始为应用程序的数据库模型工作。
在创建模型的过程中,我们发现一些模型之间或与其他数据之间确实有一些关系。例如,一个用户可能有一个特定的ID,这样,这个特定的ID也指的是用户,但我们如何告诉数据库这种共生关系的存在呢?
要做到这一点,我们首先需要了解基本的数据库关系以及它们在我们的模型中是如何被初始化的。
数据库关系
在与数据库打交道的过程中,以下是你在与表打交道时经常会遇到的两类关系。
- 一对多
- 一对一
在我们对各种数据库关系的理解中,考虑创建一个宠物管理系统。该应用程序将由以下模型组成。PetHandler,PetCategory, 和PetComment ,如下图所示。
# pet handler class
class PetHandler(db.Model):
# create handler id column
handler_id = db.Column(db.Integer, primary_key = True)
# create handler name column
handler_name = db.Column(db.String(150), nullable = False)
# pet category class
class PetCategory(db.Model):
# create pet id column
pet_id = db.Column(db.Integer, primary_key = True)
# create pet name column
pet_name = db.Column(db.String(100), nullable = False)
# create pet category column
pet_category = db.Column(db.String(50), nullable = False )
class PetComnment(db.Model):
# create comment id column
comment_id = db.Column(db.Integer, primary_key = True)
# create comment content column
comment_content = db.Column(db.String(200), nullable = False)
你可能不理解上面代码的实现,但是关注数据库关系的概念,我们就会进入到创建数据库的组件的重点。
一对多的关系
从我们的宠物管理系统作为类比,在PetCategory ,分析了一个宠物管理员和宠物之间的一对多关系的例子,这样,一个宠物管理员可以被分配到多个(许多)宠物去照顾。
这种关系在我们的模型中的表现是通过以下过程。
我们在PetCategory 类中创建一个包含ForeignKey() 的列。简单地说,宠物管理人是与宠物有多重关系的属性,因此宠物将有一列包含一个ForeignKey() 到宠物管理人的唯一识别键,即宠物管理人的IDhandler_id 。
# create pet category table
class PetCategory(db.Model):
# create pet id, name, category column
pet_id = db.Column(db.Integer, primary_key = True)
pet_name = db.Column(db.String(100), nullable = False)
pet_category = db.Column(db.String(50), nullable = False )
# create a handler id column establishing a relationship with the foreign key class table
handler_id = db.Column(db.Integer, db.ForeignKey('pethandler.handler_id'), nullable = False)
最后一行代码,用handler_id 变量名称,初始化了宠物管理人和宠物之间存在的一对多关系。db.ForeignKey 接收一个参数,指向pethandler表中的handler_id 列。
注意,pethandler 类的名称必须是小写的,这告诉SQLAlchemy我们是指一个表。
现在,宠物们意识到了来自处理程序的关系,但是处理程序表还没有意识到与任何表的关系。
要做到这一点,我们必须在PetHandler 类中添加一行代码。
# create pet handler table
class PetHandler(db.Model):
# create pet handler id and handler name column
handler_id = db.Column(db.Integer, primary_key = True)
handler_name = db.Column(db.String(150), nullable = False)
# initialize the relationship from the pet handler table with pet category table
pet_category = db.relationship('PetCategory', backref='pet_handler', lazy = True)
在PetHandler 类中,我们写了代码来通知处理程序它与PetCategory 表有关系。backref 参数在PetCategory 表中创建了一个pet_handler 虚拟变量,这样我们就可以通过使用PetCategory.pet_handler 来访问宠物的处理程序。
在flask中创建一个模型
有了对两种最常见的数据库关系的坚定理解,我们就可以在flask web应用程序中创建模型,以存储用户的注册数据。
要定义一个模型,我们可以遵循下面的模板。
class ModelTableName(db.Model):
#table column unique id with a primary key
data_column_uniqueid = db.Column(db.Integer, primary_key = True)
#table column field with data type
data_column_field = db.Column(db.ColumnDataType, nullable = False)
在定义模型的过程中,一个模型必须有一个唯一的ID,作为其主键,这是你在模型表中定义的第一件事。接下来,你可以继续为你的表定义另一个数据字段。
另外,在每一列中,你必须指定一个数据类型,如String,Integer, 或任何其他适合被存储数据的数据类型。如果你知道数据字段不应该是空的,在数据字段上设置nullable 到False 也是一个好的做法。
上述模板的实现应该是这样的。
class UserDetails(db.Model):
# table column id
user_id = db.Column(db.Integer, primary_key = True)
# table column name with data type of String
user_name = db.Column(db.String, nullable = False)
用SQLAlchemy存储用户注册数据
在对SQLAlchemy的实现有了更好的理解后,让我们通过克隆的flask网络应用来深入研究一些实际应用。现在,让我们在浏览器中导航到注册路线http://127.0.0.1:5000/register 。
我们的注册页面包含三个输入数据域,分别是用户名、电子邮件和用户密码。在本文的范围内,我们不会深入研究密码加密的问题。相反,我们将以普通格式存储我们的密码(尽管这不是一个好的做法)。
创建用户注册模型
在app 文件夹中,创建一个新的文件并命名为models.py 。在我们的模型文件中,我们定义了用户注册表的模型。
在我们的模型中,我们首先导入我们在应用__init__.py 文件中初始化的db对象
# import the db object from the flask app
from app import db
接下来让我们创建用户模型来处理用户名、电子邮件和密码的注册表单数据。
# create user table with required field
class User(db.Model):
id = db.Column(db.Integer, primary_key =True)
username = db.Column(db.String(100), nullable = False)
user_email = db.Column(db.String(100), nullable= False)
user_password = db.Column(db.String(150), nullable = False)
在模型声明中,你可以观察到传递给String 数据类型的参数包含一个要求的长度。对于db.String(100) ,预计该字符串的长度必须超过100。
接下来,在我们的__init__.py 文件中,在数据库对象初始化的下面,我们导入了模型文件。这样做的原因是,当我们创建数据库时,flask将无法访问我们models.py 文件中的数据库模型。除非我们把它引回应用初始化文件中,让数据库对象知道它的存在。
# import the models module
from app import models
在这一点上,你的__init__.py 文件应该是这样的。
# import flask and sqlaclhemy
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# app configuration
app.config["SECRET_KEY"] = '571ebf8e13ca209536c29be68d435c00'
app.config["SQLALCHEMY_DATABASE_URI"] = 'sqlite:///registration.db'
db = SQLAlchemy(app)
# import views/routes and models
from app import views
from app import models
而你的models.py 文件应该看起来完全像这样。
# import db object from flask app
from app import db
# database tables
class User(db.Model):
id = db.Column(db.Integer, primary_key =True)
username = db.Column(db.String(100), nullable = False)
user_email = db.Column(db.String(100), nullable= False)
user_password = db.Column(db.String(150), nullable = False)
我们已经创建了数据模型,现在让我们来创建这个数据库。要做到这一点,我们需要打开我们的终端到我们的工作目录,并按照这个过程进行。
初始化 Python 解释器。
$ python
接下来,从我们初始化SQLAlchemy对象实例的__init__.py 文件中导入数据库变量,然后创建数据库。
# import db object and create all tables in the database from the models file
$ >>> from app import db
$ >>> db.create_all()
记住,数据库变量是我们在__init__.py 中使用的变量名,如果你打算使用一个不同的变量,那么你必须调用那个变量名,而不是这里创建的数据库变量。
为了确认我们的数据库已经创建,检查你的应用程序文件夹,你应该看到一个名为registration.db 的新文件,这就是我们在__init__.py 文件中指定的db 名称。
接下来,我们可以使用这个命令将User 表导入我们的模型文件中。
# import the user table from the models
$ >>> from app.models import User
为了确保数据库的功能不受影响,让我们从Python解释器中创建一个假用户。
# create an instance of a user with required arguments from the database table
$ >>> user1 = User(username = "Demo User", user_email = "demouser@gmail.com", user_password = "demouserpassword")
在上面的命令中,我们为每个变量指定了在我们的User 模型中定义的数据,然后点击ENTER 键。接下来,我们要向数据库添加一个新的用户,然后提交更改。
# add the user instance to the database
$ >>> db.session.add(user1)
接下来,我们提交对数据库所做的修改。
# commit the changes to the database
$ >>> db.session.commit()
为了确认我们的数据库是否工作,我们查询数据库,它应该使用以下命令返回一个包含新用户详细信息的对象。
# query all data from the User table
$ >>> User.query.all()
注意,我们查询的是User 表。
现在,我们可以手动添加数据到注册数据库,我们如何直接通过前端添加数据到数据库?
添加用户数据到注册数据库
在我们的视图中,我们首先从我们的应用程序中导入User 模型和db 对象。
# import db object and User table
from app import db
from app.models import User
在我们的注册路线逻辑中,我们创建一个用户对象,并将我们从前面的教程中获取的数据存储在用户模型列中。
@app.route("/register", methods=["GET", "POST"])
def register():
# check the request method to ensure the handling of POST request only
if request.method == "POST":
# store the form value
user_name = request.form["username"]
email = request.form["email"]
password = request.form["password"]
# create an instance of the user table
user = User(username = user_name, user_email = email, user_password = password)
return username + " <br/> " + email
return render_template('register.html')
接下来,我们添加用户并向数据库提交更改,我们用 "用户注册成功 "替换返回语句。
在实现的最后,你的注册路线应该是这样的。
@app.route("/register", methods=["GET", "POST"])
def register():
#check the request method to ensure the handling of POST request only
if request.method == "POST":
#store the form value
user_name = request.form["username"]
email = request.form["email"]
password = request.form["password"]
# store the user details in the user database table
user = User(username = user_name, user_email = email, user_password = password)
# add the user object to the database
db.session.add(user)
# commit changes to the database
db.session.commit()
return 'User registration successful'
return render_template('register.html')
测试运行我们的应用程序
让我们来测试运行我们的应用程序。如果你的服务器正在运行,终止并重新启动。现在,你应该让你的服务器运行,然后进入你的网络应用的注册页面。
让我们在数据库中填入这些假数据:username 为Peter ,email 为peterdury@gmail.com ,password 为password 。

我们收到了注册成功的消息,但让我们检查一下数据库,看看我们的用户数据是否被存储。
# import db and User table
$ >>> from app import db
$ >>> from app.models import User
# query User table
$ >>> User.query.all()
$ [<User 1>, <User 2>]
当你按顺序运行下面的命令时,你应该得到一个响应,表明新的用户被添加。在我们的例子中,我们已经手动添加了一个用户,由于注册,我们现在有一个新的用户。
让我们深入研究一下,运行一个新的命令,通过注册用户的用户名查询用户表。
$ >>> user_data = User.query.all() # store queried data in the user_data variable
$ >>> for user in user_data: # loop through the user data
print(user.username)
如果你按顺序运行这些代码片断,你应该可以得到数据库中所有注册用户的用户名数据。
$ Demo user
$ Peter
总结
本文涵盖了SQLAlchemy在构建Flask Web应用程序时的用法,存储数据,通过Python解释器访问存储数据,以及数据库建模。
我们还介绍了在构建数据库模型时可能存在的数据库关系类型。
作为提高技能的实践测试,尝试在你的flask web应用中创建一个联系表单,然后将内容存储在你的自定义数据库中。