Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog

目录

前文列表

用 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 SQLAlchemy
from main import app # INIT the sqlalchemy object
# Will be load the SQLALCHEMY_DATABASE_URL from config.py
db = 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 = id
self.username = username
self.password = password def __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)
>>> db.session.commit()

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

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.username
u'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.page
1 # 获取总共的页数
>>> user_page.pages
1 # 是否有上一页
>>> user_page.has_prev
False # 如果有上一页的话, 获取上一页的 pagination 对象
>>> if user_page.has_prev:
... user_page.prev()
... # 是否有下一页
>>> user_page.has_next
False # 如果有下一页的话, 获取下一个的 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.username
u'fanguiju' >>> user = db.session.query(User).update({'username': 'update_fanguiju'})
>>> db.session.commit() >>> user = db.session.query(User).first()
>>> user.username
u'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)
>>> db.session.commit()

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

用 Flask 来写个轻博客 (5) — (M)VC_SQLAlchemy 的 CRUD 详解的更多相关文章

  1. 用 Flask 来写个轻博客

    用 Flask 来写个轻博客 用 Flask 来写个轻博客 (1) — 创建项目 用 Flask 来写个轻博客 (2) — Hello World! 用 Flask 来写个轻博客 (3) — (M)V ...

  2. 用 Flask 来写个轻博客 (37) — 在 Github 上为第一阶段的版本打 Tag

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 第一阶段结语 打 Tag 前文列表 用 Flask 来写个轻博客 (1 ...

  3. 用 Flask 来写个轻博客 (36) — 使用 Flask-RESTful 来构建 RESTful API 之五

    目录 目录 前文列表 PUT 请求 DELETE 请求 测试 对一条已经存在的 posts 记录进行 update 操作 删除一条记录 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 ...

  4. 用 Flask 来写个轻博客 (35) — 使用 Flask-RESTful 来构建 RESTful API 之四

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 POST 请求 身份认证 测试 前文列表 用 Flask 来写个轻博客 ...

  5. 用 Flask 来写个轻博客 (34) — 使用 Flask-RESTful 来构建 RESTful API 之三

    目录 目录 前文列表 应用请求中的参数实现 API 分页 测试 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Flask 来写个轻博客 (2) - Hello World! 用 F ...

  6. 用 Flask 来写个轻博客 (33) — 使用 Flask-RESTful 来构建 RESTful API 之二

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 构建 RESTful Flask API 定义资源路由 格式 ...

  7. 用 Flask 来写个轻博客 (32) — 使用 Flask-RESTful 来构建 RESTful API 之一

    目录 目录 前文列表 扩展阅读 RESTful API REST 原则 无状态原则 面向资源 RESTful API 的优势 REST 约束 前文列表 用 Flask 来写个轻博客 (1) - 创建项 ...

  8. 用 Flask 来写个轻博客 (31) — 使用 Flask-Admin 实现 FileSystem 管理

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 编写 FileSystem Admin 页面 Flask-A ...

  9. 用 Flask 来写个轻博客 (30) — 使用 Flask-Admin 增强文章管理功能

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 实现文章管理功能 实现效果 前文列表 用 Flask 来写个 ...

随机推荐

  1. xcodebuild 自动化打包

    altool 文档 使用xcode自带的xcodebuild 命令通过脚本进行打包 打包->导出ipa, 两行关键的脚本代码 1.Archive xcodebuild archive -arch ...

  2. Shell逻辑运算符及表达式

    一. 运算符总结说明 1. 条件运算符 运算符号 代表意义 应用 说明 = 等于 整型或字符串比较: str1 = str2 字符串str1 和字符串str2 相等时返回真,如果在[]中,只能是字符串 ...

  3. How to show out three rows from the same databand On A4?

    How to show out three rows from the same databand On A4? Quote Post by DoraHuang » Tue Mar 13, 2018 ...

  4. apache基础,apache环境搭建,apache的3种使用方式(IP、端口、域名)

    一台服务器上多个网站同时运行,基于域名访问,IP访问,端口访问. http服务使用的端口是80 HTTPS使用的是443 协议名称://机器地址:端口号/路径名/文件名 协议名称—— 所使用的访问协议 ...

  5. java File I/O

    File类: 常用方法: boolean exists( ):判断文件或目录是否存在 boolean isFile( ):判断是否是文件 boolean isDirectory( ):判断是否是目录 ...

  6. 关于array_merge()的注意

    array_merge() 函数把两个或多个数组合并为一个数组. 1 如果键名有重复,该键的键值为最后一个键名对应的值(后面的覆盖前面的). 2 如果数组是数字索引的,则键名会以连续方式重新索引. 2 ...

  7. Elasticsearch学习,请先看这一篇

    题记: Elasticsearch研究有一段时间了,现特将Elasticsearch相关核心知识.原理从初学者认知.学习的角度,从以下9个方面进行详细梳理.欢迎讨论-- 0. 带着问题上路--ES是如 ...

  8. 【摘】Linux虚拟地址空间布局以及进程栈和线程栈总结

    在CSDN上看到的一篇文章,讲的还是满好的. 原文地址:Linux虚拟地址空间布局以及进程栈和线程栈总结 一:Linux虚拟地址空间布局 (转自:Linux虚拟地址空间布局) 在多任务操作系统中,每个 ...

  9. shell数学运算

    shell的数学运算 branches@ubuntu:~$ var1=$[ * ] branches@ubuntu:~$ echo $var1 branches@ubuntu:~$ var2=$[$v ...

  10. struts2之ModelDriven

    在Struts 2中,提供了另外一种直接使用领域对象的方式,就是让action实现com.opensymphony. xwork2.ModelDriven接口.ModelDriven让你可以直接操作应 ...