SQLAlchemy 模型使用
模型定义
对于 Table 的定义, 本来是直接的实例化调用, 通过 declarative
的包装, 可以像”定义类”这样的更直观的方式来完成.
1 | user = Table('user', metadata, |
1 | # -*- coding: utf-8 -*- |
创建
1 | session = Session() |
执行的顺序并不一定会和代码顺序一致, SQLAlchemy 自己会整合逻辑再执行.
查询
SQLAlchemy 实现的查询非常强大, 写起来有一种随心所欲的感觉.
查询的结果, 有几种不同的类型, 这个需要注意, 像是:
- instance
- instance of list
- keyed tuple of list
- value of list
基本查询
1 | session.query(User).filter_by(username='abc').all() |
多表查询
1 | session.query(Blog, User).filter(Blog.user == User.id).first().User.username |
条件查询
1 | from sqlalchemy import or_, not_ |
函数
1 | from sqlalchemy import func |
修改
还是通常的两种方式:
1 | session.query(User).filter(User.username == 'abc').update({'name': '123'}) |
如果涉及对属性原值的引用, 则要考虑synchronize_session
这个参数.
evaluate
默认值, 会同时修改当前 session 中的对象属性.fetch
修改前, 会先通过 select 查询条目的值.False
不修改当前 session 中的对象属性.
在默认情况下, 因为会有修改当前会话中的对象属性, 所以如果语句中有 SQL 函数, 或者”原值引用”, 那是无法完成的操作, 自然也会报错, 比如:
1 | from sqlalchemy import func |
这种情况下, 就不能要求 SQLAlchemy 修改当前 session 的对象属性了, 而是直接进行数据库的交互, 不管当前会话值:
1 | session.query(User).update({User.name: User.name + 'x'}, synchronize_session=False) |
是否修改当前会话的对象属性, 涉及到当前会话的状态. 如果当前会话过期, 那么在获取相关对象的属性值时, SQLAlchemy 会自动作一次数据库查询, 以便获取正确的值:
1 | user = session.query(User).filter_by(username='abc').scalar() |
执行了update
之后, 虽然相关对象的实际的属性值已变更, 但是当前会话中的对象属性值并没有改变. 直到session.commit()
之后, 当前会话变成”过期”状态, 再次获取user.name
时, SQLAlchemy 通过user
的 id
属性, 重新去数据库查询了新值. (如果 user 的 id 变了呢? 那就会出事了啊.)synchronize_session
设置成 fetch
不会有这样的问题, 因为在做 update 时已经修改了当前会话中的对象了.
不管 synchronize_session
的行为如何, commit
之后 session
都会过期, 再次获取相关对象值时, 都会重新作一次查询.
删除
1 | session.query(User).filter_by(username='abc').delete() |
删除同样有像修改一样的 synchronize_session 参数的问题, 影响当前会话的状态.
JOIN
SQLAlchemy 可以很直观地作 join 的支持:
1 | r = session.query(Blog, User).join(User, Blog.user == User.id).all() |