跳转至

24 数据库应用(四):如何在项目中灵活应用数据库操作

你好,我是Barry。

在我们项目开发过程中,为了实现各式各样的开发需求,离不开对数据的管理。而数据管理就需要操作数据库来实现。通过前面课程的学习,我们对数据库操作建立了基本认识,但并没有真正在项目里应用起来。

说到数据库操作,我们都知道它的核心就是对数据库中的数据实现增、删、改、查这些操作。你会发现万变不离其宗,所有的业务需求都是通过单一的操作或者组合操作来实现的,所以我们一定要非常熟悉数据库每种操作方法的实现方式,未来才能应对更复杂的需求场景。

今天是一节实操练习课,耐心跟着我的思路和操作步骤学完今天的内容,你就可以独立实现数据库里的所有操作,真正做到学以致用。

数据库新增(create)

数据库实操之旅的第一站,我们先来完成数据库的新增操作。你可以对照文稿里具体执行方法的代码,听我讲解。

db.session.add()
db.session.commit()

这段代码的作用很容易理解,db.session是 SQLAlchemy 框架中的一个抽象概念,是一个可以注册所有数据库操作的上下文管理器。它的作用就是连接数据源并持续跟踪所有数据库操作,这样我们就能更清晰地把握数据库里发生的各种操作了。

为了帮你加深理解,我们结合案例来练习一下。当我们想要通过编写代码添加一个新的数据库记录时,就可以操作 ‘db.session.add()’ 将数据添加到会话中,并通过 ‘db.session.commit()’ 将更改提交到数据库。语句db.session.add()当中传入的参数,就表示UserInfo的一个实例化对象。

如果我们想要增添一条信息,完整语句应该是后面这样。

new_user = UserInfo(nickname="new_user", mobile="13812341234", sex='1')
db.session.add(new_user)
db.session.commit()

这里我们要注意UserInfo中的参数,除了有默认值的字段外,其余字段都需要设置。为了让我们后续的工作更轻松高效,对于这类重复性的操作,我们可以在模型基类中提前添加上共用的操作,我们依次来看看都有哪些操作。

首先,我们要在base.py文件中定义的模型基类BaseModel类中添加操作。注意在这里不要额外设置查询函数,因为每个查询方式和查询条件可能都不一样,无法统一定义。

def add(self, obj):
    db.session.add(obj)
    return session_commit()
def update(self):
    return session_commit()
def delete(self):
    self.status = 0
    return session_commit()

我还给你准备了完整的base.py的代码,你可以参考一下。

from datetime import datetime
from api import db
from api.libs.db_utils import session_commit
class BaseModels:
    """模型基类"""
    # 创建时间
    create_time = db.Column(db.DateTime, default=datetime.now)
    # 记录你的更新时间
    update_time = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now)
    # 记录存活状态
    status = db.Column(db.SmallInteger, default=1)
    def add(self, obj):
        db.session.add(obj)
        return session_commit()
    def update(self):
        return session_commit()
    def delete(self):
        self.status = 0
        return session_commit()

同时,我们再学习一个优化精简代码的实用方法——把session_commit()函数单独管理起来。我们可以把这个函数放在api文件夹下的libs中,然后新建db_utils.py文件,具体的代码是后面这样。

from sqlalchemy.exc import SQLAlchemyError
from api import db
def session_commit():
    try:
        db.session.commit()
    except SQLAlchemyError as e:
        db.session.rollback()
        reason = str(e)
        return reason

这里我想提醒你的是,别忘了全面考虑,做好程序的异常处理。如果无异常就正常执行,提交请求;如果出现异常,则要使用db.session.rollback()实现回滚操作,并且以字符形式返回异常类型。

接下来,我们就一起实现在数据库里添加数据。在app.py文件中的具体执行代码我放在了后面。

@app.route('/add')
def add_data():
    u = UserInfo()
    new_user1 = UserInfo(nickname='flask_test1', mobile='13323456789', signature='理想', create_time=datetime.now(), role_id=1)
    new_user2 = UserInfo(nickname='flask_test2', mobile='13312345678', signature='梦想', create_time=datetime.now(), role_id=2)
    new_user1 = UserInfo(nickname='flask_test3', mobile='13311223344', signature='理想', create_time=datetime.now(), role_id=3)
    new_user2 = UserInfo(nickname='flask_test4', mobile='13333445566', signature='梦想', create_time=datetime.now(), role_id=4)
    u.add(new_user1)
    u.add(new_user2)
    u.add(new_user3)
    u.add(new_user4)

接下来,我们要在pycharm终端运行后面这条命令。

python app.py runserver

这条命令执行后会启动一个本地服务器,让你的 Python 应用程序可以在一个本地端口上运行打开浏览器。之后我们还要浏览器输入 127.0.0.1:5000/add,这样我们就实现了新增操作。后面是具体的命令执行图和浏览器效果图,供你参考。


进行到这里,你会发现界面中会显示服务器错误,这是怎么回事儿呢?别担心,这是因为我们现在只是操作了数据库,并没有进行任何与服务器相关的操作。

完成了添加操作以后,这时候你打开Navicat,就会看到数据库表中我们已经添加了这四条记录。到这里,我们就成功实现了对数据库的新增操作。

数据库查询(query)

我们已经知道了如何向数据库里添加记录,那么如何从数据库里取回数据呢?

我们通过使用模型类提供的query属性,附加调用各种过滤方法及查询方法就可以完成这个任务。

一般来说,一个完整的查询遵循下面的模式。

<模型类>.query.<过滤>.<查询>

SQLAlchemy提供了许多查询方法,我用表格梳理了其中用来获取数据的方法。虽然方法不少,但不要紧张,表里的内容你也不用刻意记,随用随取,多加练习即可。

看到这里估计你还有疑问,我们具体该如何使用这些方法呢?

我们这就结合案例来继续学习。我们从all()开始说起。这里我们使用UserInfo模型基类query属性的all()方法,就能够查询到用户表里的所有信息。

user_list = UserInfo.query.all()
print(user_list)

其他的方法大同小异,你可以参考我提供的形式自己尝试一下,相信练习后你就能非常熟练地掌握这些查询方法了。

接下来,我们来挑战一个综合性的应用实践——加上自定义的路由来尝试执行不同的查询方式。完整代码是后面这样。

@app.route('/query1')
def query_data1():
    user_list = UserInfo.query.all()
    result = []
    for user in user_list:
        result.append(user.to_dict())
    return {'users': result}
@app.route('/query2')
def query_data2():
    user = UserInfo.query.get(3)
    return {'users': user.to_dict()}
@app.route('/query3')
def query_data3():
    first_user = UserInfo.query.first()
    return {'users': first_user.to_dict()}
@app.route('/query4')
def query_data4():
    user_list = UserInfo.query.filter(UserInfo.signature == '理想').all()
    result = []
    for user in user_list:
        result.append(user.to_dict())
    return {'users': result}
@app.route('/query5')
def query_data5():
    user_list = UserInfo.query.filter_by(signature='理想').all()
    result = []
    for user in user_list:
        result.append(user.to_dict())
    return {'users': result}

加上了路由后,我们需要在模型基类中使用方法to_dict,目的是将数据变成在前端能响应的JSON格式。这时候。你直接执行运行命令就能看到效果了。我们在浏览器中分别输入下面的路由。

127.0.0.15000/query1
127.0.0.15000/query2
127.0.0.15000/query3
127.0.0.15000/query4
127.0.0.15000/query5

到这里,我们就完成了对数据库数据查询的操作。

数据库删除(Delete)

学完了数据库新增和查询操作,下面我们来看看删除操作。

对于删除操作,我们同样需要使用session这个对象来实现,我们还是结合具体的实现方法代码来理解。

db.session.delete(delete_user)
db.session.commit()

可以看到,这里和添加操作不同的地方是db.session.add()方法变成了db.session.delete()方法,但同样需要传入一个参数。删除时,delete_user需要通过查询语句先完成查询操作,找到要删除的记录,然后再执行删除操作。

例如我们想要删除id为4的用户信息,就可以像后面这样操作。

@app.route('/delete')
def delete_data():
    delete_user = UserInfo.query.get(4)
    db.session.delete(delete_user)
    db.session.commit()

运行程序之后,我们需要在浏览器中输入下面的路由。

127.0.0.15000/delete

这时候,我们在数据库中就会发现id为4的记录已经删除了,你可以参考后面的截图看一下。

刚才讲的这种删除方式,效果是永久删除这条记录,但是实际情况可能存在误删,那我们怎么应对才更好呢?

这就需要我们在模型基类中自定义删除方法,将status存活状态设置为0。

@app.route('/delete')
def delete_data():
    delete_user = UserInfo.query.get(3)
    delete_user.delete()

同样运行程序之后,我们还要在浏览器中输入下面的域名,随后你就会在数据库中看到对应执行的效果了。

127.0.0.15000/delete


可以看到,这时记录还在,但是存活状态为0。这样一来,我们在写业务逻辑部分的时候,使用satus即可判断数据的状态。

数据库更新(Update)

数据库更新操作,其实就是数据库修改操作,它在项目开发里的使用频率也非常高。比方说修改用户信息、修改视频信息都会用得上。

跟之前的删除操作思路一样,更新操作也要先查询信息。而不同的地方是,我们不再借助session这个对象传递数据,只需要使用语句db.session.commit()方法提交修改的信息即可。

为了帮你更直观地理解,我们结合例子来看看。现在我们希望把前面修改过的第三条记录撤销掉,也就是把这条记录的存活状态设置回来,那具体的实现方法就是后面这样。

@app.route('/update')
def update_data():
    u = UserInfo()
    update_user = u.query.get(3)
    update_user.status = 1
    u.update()

看过代码和效果图之后,是不是感觉一通百通了呢?到这里我们就完成了数据库的所有操作。当然,我们在项目开发过程中结合实际业务需求,也会出现组合使用的情况,例如在项目中想要修改个人信息,我们需要先查询个人信息,获取到数据之后再修改。不过不用担心,我们掌握了每一项基本操作的方法,组合起来应用也难不倒你。

总结

又到了课程的尾声,让我们梳理总结一下今天的内容重点。

今天的实操练习当中,我们通过代码案例分别实现了数据库的增、删、改、更新,进一步强化了我们的数据库操作技能。

项目开发里离不开数据库的数据管理,无论是调整、更新视频信息,还是管理用户的信息表,都需要用到数据库里增、删、改、查这些操作。另外,实现的过程中我们多次用到db.session,它是 SQLAlchemy 框架中的一个抽象概念,用来连接数据源并持续跟踪所有数据库操作。

其实在项目里完成数据库操作其实并不复杂,你也应该感受到了,真正落地的时候仍然需要你具备灵活处理的思维和扎实的代码功底。课程里我为你详细梳理了各个操作的代码实现逻辑,不过还是建议你课后多练习巩固,这样才能熟练掌握这些技巧。

思考题

除了在视图函数中完成增、删、改、查操作以外,在Flask shell的交互式命令行里还可以进行哪些操作呢?

欢迎你在留言区和我交流互动,也推荐你把这节课分享给身边更多朋友。

精选留言(2)
  • Aegean Sea 👍(0) 💬(1)

    为什么我执行控制台输入python app.py runserver后,Navicat里面数据库没有新增falsk_test1-flask_test4

    2023-11-03

  • peter 👍(0) 💬(2)

    Q1:数据库连接的session怎么理解? 对于数据库的session,感觉一直理解不到位。一个用户连到数据库,从建立连接到中断连接,这整个过程是一个session吗?另外,session是对应于TCP连接吗? 即session = TCP连接,可以这么理解吗? Q2:runserver是指什么? “python app.py runserver”,其中的runserver是一个命令,关键字,不是一个server的名字吧。 这个命令会启动一个server吗?哪里的server?是python库里自带的一个server吗? Q3:update并没有用session. Update部分,有一句“不同的地方是,我们不再借助 session 这个对象传递数据,只需要使用语句 db.session.commit() 方法提交修改的信息即可”,提到了用session.commit,但是代码中并没有session.commit: def update_data(): u = UserInfo() update_user = u.query.get(3) update_user.status = 1 u.update()

    2023-06-16