1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 用 Flask 来写个轻博客 (5) — (M)VC_SQLAlchemy 的 CRUD 详解

用 Flask 来写个轻博客 (5) — (M)VC_SQLAlchemy 的 CRUD 详解

时间:2019-04-23 05:29:49

相关推荐

用 Flask 来写个轻博客 (5) — (M)VC_SQLAlchemy 的 CRUD 详解

Blog 项目源码:/JmilkFan/JmilkFan-s-Blog

目录

目录前文列表扩展阅读SQLAlchemy 的 CRUDCreate 增添数据Retrieve 读取数据限制返回记录的数目返回记录的排序查询函数的链式调用Flask-SQLAlchemy 的专有分页函数 paginationQuery 的过滤器 Update 更新数据Delete 删除数据

前文列表

用 Flask 来写个轻博客 (1) — 创建项目

用 Flask 来写个轻博客 (2) — Hello World!

用 Flask 来写个轻博客 (3) — (M)VC_连接 MySQL 和 SQLAlchemy

用 Flask 来写个轻博客 (4) — (M)VC_创建数据模型和表

扩展阅读

SQLAlchemy 的 CRUD

CRUD 提供了在 Web 应用程序中所需要的所有操作和检视数据的基础功能, 尤其在 REST 风格的应用中, CRUD 就能实现一切所需功能.

本篇博文主要记录 SQLAlchemy 实现 CRUD 的语句, 依然是在 manager shell 中完成:

(blog)fanguiju@fanguiju:/opt/JmilkFan-s-Blog$ python manage.py shell>>> app<Flask 'main'>>>> User<class 'models.User'>>>> db<SQLAlchemy engine='mysql+pymysql://root:fanguiju@127.0.0.1:3306/myblog?charset=utf8'>

为了让在 manager shell 中的执行效果更直观一些, 首先, 先对 User models 做一些修改:

from flask.ext.sqlalchemy import SQLAlchemyfrom main import app# INIT the sqlalchemy object# Will be load the SQLALCHEMY_DATABASE_URL from config.pydb = SQLAlchemy(app)class User(db.Model):"""Represents Proected users."""# Set the name for table__tablename__ = 'users'id = db.Column(db.String(45), primary_key=True)username = db.Column(db.String(255))password = db.Column(db.String(255))def __init__(self, id, username, password):self.id = idself.username = usernameself.password = passworddef __repr__(self):"""Define the string format for instance of User."""return "<Model User `{}`>".format(self.username)

Create 增添数据

为新建的 User models 添加一条记录的操作看起来跟 Git 的提交操作非常类似, 其包含的意义也大致相同, 是为了尽量减少不必要的 I/O 操作:

add: 把数据添加到会话对象中 (数据状态为待保存)commit: 将会话对象中的数据提交 (数据被写入数据库中)

>>> from uuid import uuid4>>> user = User(id=str(uuid4()), username='jmilkfan', password='fanguiju')>>> db.session.add(user)>>> mit()

然后再查看一下数据库, 检验是否生效:

mysql> select * from users;+--------------------------------------+----------+----------+| id| username | password |+--------------------------------------+----------+----------+| d2c3a206-c4d4-4ce9-91f1-ed4bbbb28c76 | jmilkfan | fanguiju |+--------------------------------------+----------+----------+1 row in set (0.00 sec)

从这个例子可以看出, 一个 class User 的实例化对象就是一条包含了字段值的记录对象, 将该记录对象添加并提交到 session , 就会把记录对象的数据写入到数据库中.

Retrieve 读取数据

把数据添加仅数据库表后, SQLAlchemy 可以通过Model.query方法对数据进行查询.Model.query == db.session.query(Model)两种写法是等效的. 区别在于前者使用的是flask_sqlalchemy.BaseQuery object, 后者使用的是sqlalchemy.orm.query.Query object. 但两者本质上都是一个Query对象.

读取数据有两种情况:

读取一条数据: 需要指定唯一的过滤条件来获取, 一般会使用主键作为过滤条件.

>>> user = User.query.first()>>> user.usernameu'fanguiju'# 返回表中的第一条记录# 其中 User.query 返回的是 flask_sqlalchemy.BaseQuery object# flask_sqlalchemy.BaseQuery object 拥有对数据库操作的所有抽像方法# or>>> user = User.query.get('49f86ede-f1e5-410e-b564-27a97e12560c')>>> user<Model User `fanguiju`># 返回表中指定主键的一条记录# or>>> user = db.session.query(User).filter_by(id='49f86ede-f1e5-410e-b564-27a97e12560c').first()>>> user<Model User `fanguiju`># 返回符合过滤条件的第一条记录# 其中 db.session.query(User).filter_by(id='49f86ede-f1e5-410e-b564-27a97e12560c') 返回的是一个 sqlalchemy.orm.query.Query object 对象# sqlalchemy.orm.query.Query.first() 才是一个 User 对象

读取多条数据: 指定任意条件作为过滤条件或者不过滤的获取全部数据

# 获取多条记录>>> user = db.session.query(User).filter_by(username='fanguiju').all()>>> user[<Model User `fanguiju`>]# 返回符合过滤条件的所有记录, 将所有 username == fanguiju 的记录都获取# 获取全部数据>>> users = User.query.all()>>> users[<Model User `fanguiju`>, <Model User `jmilkfan`>]# or>>> db.session.query(User).all()[<Model User `fanguiju`>, <Model User `jmilkfan`>]

NOTE: 因为在 Flask 中的 SQLAlchemy 拥有 flask-sqlalchemy 和 sqlalchemy.orm 两种语法, 为了避免看花眼的情况, 以后的代码中只会使用通用性更强一些的 sqlalchemy.orm 的语法.

除了上述两种操作之外, 还有非常之多不同花样的数据读取方式, 读取数据是 4 种操作类型中最复杂多样的一中操作类型.

限制返回记录的数目

这个返回特征常与数据的分页功能结合使用.

>>> users = db.session.query(User).limit(10).all()

返回记录的排序

SQLAlchemy 默认会根据主键的顺序来排序, 也是要显示的使用order_by函数来指定排序条件和排序的方式:

# 正向排序>>> users = db.session.query(User).order_by(User.username).all()>>> users[<Model User `fanguiju`>, <Model User `jmilkfan`>]# 反向排序>>> users = db.session.query(User).order_by(User.username.desc()).all()>>> users[<Model User `jmilkfan`>, <Model User `fanguiju`>]>>> users = db.session.query(User).order_by(User.password).all()>>> users[<Model User `jmilkfan`>, <Model User `fanguiju`>]

查询函数的链式调用

Query对象提供了非常多且灵活的数据库操作抽象方法, 我们可以链式的去组合这些方法来达到希望的效果.但需要注意的是, 删除操作的链式调用一定要谨慎而为.

>>> users = db.session.query(User).order_by(User.username).limit(10).all()

可以使用 dir() 内置函数来查看一个Query对象提供的方法列表.

dir(db.session.query(User))

NOTE: 一条读取语句的链式操作都是一个first()all()函数结束的. 它们会终止链式调用并返回结果.

Flask-SQLAlchemy 的专有分页函数 pagination

pagination(): 是专门设计来实现分页功能的函数, 所以必须由flask_sqlalchemy.BaseQuery object来调用.

>>> db.session.query(User).paginate(1,1)Traceback (most recent call last):File "<console>", line 1, in <module>AttributeError: 'Query' object has no attribute 'paginate'

第一个参数表示查询返回第几页的内容第二个参数表示每页显示的对象数量

>>> User.query.paginate(1,10)# 查询第 1 页,且 1 页显示 10 条内容<flask_sqlalchemy.Pagination object at 0x7f214419fe50>

paginate()first()/all()不同, 后者返回的是一个 models 对象或 models 对象列表, 而前者返回的是一个 pagination 对象. 而且 pagination 对象还包含了几个特有的属性:

>>> user_page = User.query.paginate(1, 10)# 获取这一页所包含的数据对象>>> user_page.items[<Model User `fanguiju`>, <Model User `jmilkfan`>]# 获取这一页的页码>>> user_page.page1# 获取总共的页数>>> user_page.pages1# 是否有上一页>>> user_page.has_prevFalse# 如果有上一页的话, 获取上一页的 pagination 对象>>> if user_page.has_prev:...user_page.prev()... # 是否有下一页>>> user_page.has_nextFalse# 如果有下一页的话, 获取下一个的 pagination 对象>>> if user_page.has_next:...user_page.next()...

Query 的过滤器

在查询数据时, 可以根据一定的条件集合来获得过滤后的数据. SQLAlchemy 提供了过滤器query.filter_by()query.filter(), 过滤器接受的参数就是过滤条件, 有下面几种形式:

字段键值对, EG.username='fanguiju'比较表达式, EG.User.id > 100逻辑函数, EG.in_/not_/or_

EXAMPLE:

>>> user = db.session.query(User).filter(User.username.in_(['fanguiju', 'jmilkfan'])).limit(1).all() # 当然也可以结合链式函数来使用>>> user[<Model User `fanguiju`>]>>> user = db.session.query(User).filter(not_(User.password == None)).all()>>> user[<Model User `fanguiju`>, <Model User `jmilkfan`>]>>> user = db.session.query(User).filter(or_(not_(User.username == None), User.password != None)).all()>>> user[<Model User `fanguiju`>, <Model User `jmilkfan`>]

可以将query.filter()内置的逻辑函数in_/not_/or_结合使用来实现更复杂的过滤.

Update 更新数据

>>> user = db.session.query(User).first()>>> user.usernameu'fanguiju'>>> user = db.session.query(User).update({'username': 'update_fanguiju'})>>> mit()>>> user = db.session.query(User).first()>>> user.usernameu'update_fanguiju'

如上述例子, 先定位到你希望更新的记录, 然后通过 Query 对象的update()传递要更新内容.注意: 更新的内容必须是 Dict 数据类型.

需要注意的是: 就如使用原生 SQL 指令来更新记录一样, 如果没有指定要更新具体的哪一条记录的话, 会将该字段所在列的所有记录值一同更新, 所以切记使用过滤条件来定位到具体需要更新的记录.

而且update()会自动的添加 User 的实例化对象到 session 中, 所以直接 commit 就可以写入到数据库了.

Delete 删除数据

>>> user = db.session.query(User).first()>>> user<Model User `update_fanguiju`>>>> db.session.delete(user)>>> mit()

将查询返回的 User 实例化对象进行 session 的 delete 操作, 就能够删除该对象所映射的记录数据了.

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。