Python 数据库操作 SQLAlchemy的示例代码


Posted in Python onFebruary 18, 2019

程序在运行过程中所有的的数据都存储在内存 (RAM) 中,「RAM 是易失性存储器,系统掉电后 RAM 中的所有数据将全部丢失」。在大多数情况下我们希望程序运行中产生的数据能够长久的保存,此时我们就需要将数据保存到磁盘上,无论是保存到本地磁盘,还是通过网络保存到服务器上,最终都会将数据写入磁盘文件。将数据保存在磁盘中我们需要面对一个数据格式的问题,此时就需要引入数据库操作。

数据库是专门用于数据的集中存储和查询的软件,它便于程序保存和读取数据,且能够通过特定的条件查询指定的数据。

Python 的标准数据库接口为 Python DB-API,它为编程人员提供了完善的数据库应用标称接口。但是使用 Python DB-API 需要开发人员自行去拼接 SQL,并把 SQL 做成模板。此时全靠编程人员来保证系统的安全性,完全有人来保证系统的安全性,不可避免的会出现错误,为了减少人为原因产生的错误 ORM 框架应运而生。

ORM 即 Object-Relational Mapping,把关系数据库的表结构映射到对象上面。负责这个转换过程的就是 ORM 框架

Python 中的 ORM 框架主要有 SQLObject、Storm、Django's ORM、peewee、SQLALchemy。每种 ORM 框架都有各自的特点和相应的应用范围,本文主要介绍 SALALchemy,若你对其他框架感兴趣请自行搜索相关内容。

SQLAlchemy 简介

SQLAlchemy 是一个功能强大的开源 Python ORM 工具包。它提供了 “一个知名企业级的持久化模式的,专为高效率和高性能的数据库访问设计的,改编成一个简单的 Python 域语言的完整套件”。它采用了数据映射模式(像 Java 中的 Hibernate)而不是 Active Record 模式(像Ruby on Rails 的 ORM)。

SQLAlchemy官网。

SQLAlchemy 的优缺点:

优点:

  • 企业级 API,使得代码有健壮性和适应性。
  • 灵活的设计,使得能轻松完成复杂的数据查询。

缺点:

  • 工作单元概念不常见。
  • 重量级 API,导致长学习曲线。

SQLAlchemy 应用

以下是一段使用 SQLAlchemy 操作 SQLite 数据库的代码

# -*- coding:utf-8 -*-

from sqlalchemy import (
  create_engine,
  Column,
  Integer,
  String,
)

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

engine = create_engine('sqlite:///./sqlalchemy.sqlite', echo=True)

Base = declarative_base()

class User(Base):
  __tablename__ = 'users'

  id = Column(Integer, primary_key=True, autoincrement=True)
  name = Column(String)
  fullname = Column(String)
  nickname = Column(String)

  def __repr__(self):
    return "<User(name='%s', fullname='%s', nickname='%s')>" % (self.name, self.fullname, self.nickname)


db_session = sessionmaker(bind=engine)
session = db_session()

Base.metadata.create_all(engine)

user1 = User(name='ed', fullname='Ed Jones', nickname='edsnickname')
user2 = User(name='wendy', fullname='Wendy Williams', nickname='windy')
user3 = User(name='mary', fullname='Mary Contrary', nickname='mary')

session.add(user1)
session.add(user2)
session.add(user3)
session.commit()

user = session.query(User).filter(User.id<2).all()
print(user)
user = session.query(User).filter(User.id<=5).all()
print(user)

user1.name = 'admin'
session.merge(user1)
user4 = User(name='fred', fullname='Fred Flintstone', nickname='freddy')
session.merge(user4)
session.query(User).filter(User.id==2).update({'name':'test'})
user = session.query(User).filter(User.id<=5).all()
print(user)

在以上代码中我们完成了一下工作:

  1. 连接到数据库「本次我们使用的是 SQLite 数据库」。
  2. 创建数据库表并将其映射到 Python 类上。
  3. 创建数据实例,并将其保存到数据库中。
  4. 对保存在数据库中的数据进行读取和修改。

导入 SQLAlchemy 模块并连接到 SQLite 数据库

SQLAlchemy 通过 create_engine 函数来创建数据库连接。create_engine 函数的第一个参数是数据了 URL,第二个参数 echo 设置为 True 表示在程序的运行过程中我们可以在控制台看到操作所涉及到的 SQL 语句。

在本次示例中我们使用的数据库是 SQLite,你也可以使用其他数据库。只有在调试状态下将 echo 设置为 True,在生产环境请将 echo 设置为 false 或省略 echo 参数。

engine = create_engine('sqlite:///./sqlalchemy.sqlite', echo=True)

create_engine 返回的是一个 Engine 实例,它指向数据库的一些核心接口。SQLAlchemy会根据你选择的数据库配置而调用对应的 DB-API。

create_engine 函数并会不真正建立数据库的 DB-API 连接,当调用 Engine.execute() 或 Engine.connect() 方法时才会建立连接。大多数情况下我们无需关注 Engine,SQLAlchemy 会帮我们处理。

创建数据库表

将 python 类映射到数据库表上,这个 Python 类需要时一个指定基类的子类,这个基类应当含有ORM映射中相关的类和表的信息。这个基类可以通过 declarative_base 方法来创建。
Base = declarative_base()

在这个示例中使用 Base 基类创建了一个 User 的类来作为数据库表。

class User(Base):
  __tablename__ = 'users'

  id = Column(Integer, primary_key=True, autoincrement=True)
  name = Column(String)
  fullname = Column(String)
  nickname = Column(String)

  def __repr__(self):
    return "<User(name='%s', fullname='%s', nickname='%s')>" % (self.name, self.fullname, self.nickname)

在 User 类中我们定义了需要映射到数据库表上的属性,主要包括表名称、列的类型和名称等。这个类至少应包含一个名为 tablename 的属性来给出数据库表的名称,及至少一个给出表的主键「primary key」的列。在 User 类中我们定义了表名称为 users,定义了 id、name、fullname、nickname 四列数据,并设置 id 为表的主键。
创建完成 User 类后,实际在 SQLite 数据库中并不存在该表,此时需要使用 declarative 基类的 Metadata.create_all 在数据库中创建 users 表,在 create_all 方法中我们需要传入参数 Engine。

通过 Metadata.create_all 传入的 Engine 参数,SQLAlchemy 自动实现对数据库的连接。

Base.metadata.create_all(engine)

metadata.create_all 方法执行完成后在 SQLite 数据库即可查到名称为 users 的数据表。

保存数据实例到数据库中

将数据保存到数据库中,我们需要 User 的实例和用于操作数据的 session。

session 是 ORM 数据的接口,可以通过 session 来操作数据库中的数据。

使用已经定义完成的 User 类将数据实例化。

user1 = User(name='ed', fullname='Ed Jones', nickname='edsnickname')
user2 = User(name='wendy', fullname='Wendy Williams', nickname='windy')
user3 = User(name='mary', fullname='Mary Contrary', nickname='mary')

获取 session 首先需要使用 sessionmaker 来得到 session 的工厂类,然后通过工厂类来获取 session。

db_session = sessionmaker(bind=engine)
session = db_session()

session 通过 Engine 与数据库进行关联。session 创建完成后并不会立即打开与数据库的连接,只有当我们第一使用 session 是,才会从 Engine 维护的连接池中取出一个连接来操作数据库,这个连接在我们关闭 session 时会被释放。
获取 session 后可以通过 add 和 commit 方法将数据保存到数据库中。

session.add(user1)
session.add(user2)
session.add(user3)
session.commit()

对数据库中的数据进行查询和修改

SQLAlchemy 通过 query 来对数据进行查询,可以通过 filter 方法对查询结果进行筛选。

user = session.query(User).filter(User.id<2).all()
print(user)
user = session.query(User).filter(User.id<=5).all()
print(user)

以上代码通过 query 获取数据库中所有 User 数据,然后通过 filter 方法筛选出 id 小于 2 和 id 小于等于 5 的数据。

数据库的修改可以通过 merge 和 update 来实现

user1.name = 'admin'
session.merge(user1)
user4 = User(name='fred', fullname='Fred Flintstone', nickname='freddy')
session.merge(user4)
session.query(User).filter(User.id==2).update({'name':'test'})
user = session.query(User).filter(User.id<=5).all()
print(user)

使用 merge 修改数据,当数据中存在该数据时修改,不存在是将当前数据插入数据库中。

代码运行结果

以上示例代码的运行结果如下

2019-02-16 21:45:23,919 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
2019-02-16 21:45:23,919 INFO sqlalchemy.engine.base.Engine ()
2019-02-16 21:45:23,919 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
2019-02-16 21:45:23,919 INFO sqlalchemy.engine.base.Engine ()
2019-02-16 21:45:23,920 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("users")
2019-02-16 21:45:23,920 INFO sqlalchemy.engine.base.Engine ()
2019-02-16 21:45:23,921 INFO sqlalchemy.engine.base.Engine
CREATE TABLE users (
  id INTEGER NOT NULL,
  name VARCHAR,
  fullname VARCHAR,
  nickname VARCHAR,
  PRIMARY KEY (id)
)


2019-02-16 21:45:23,921 INFO sqlalchemy.engine.base.Engine ()
2019-02-16 21:45:23,922 INFO sqlalchemy.engine.base.Engine COMMIT
2019-02-16 21:45:23,924 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-02-16 21:45:23,925 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-02-16 21:45:23,925 INFO sqlalchemy.engine.base.Engine ('ed', 'Ed Jones', 'edsnickname')
2019-02-16 21:45:23,926 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-02-16 21:45:23,926 INFO sqlalchemy.engine.base.Engine ('wendy', 'Wendy Williams', 'windy')
2019-02-16 21:45:23,926 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-02-16 21:45:23,926 INFO sqlalchemy.engine.base.Engine ('mary', 'Mary Contrary', 'mary')
2019-02-16 21:45:23,927 INFO sqlalchemy.engine.base.Engine COMMIT
2019-02-16 21:45:23,929 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-02-16 21:45:23,929 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname
FROM users
WHERE users.id < ?
2019-02-16 21:45:23,929 INFO sqlalchemy.engine.base.Engine (2,)
[<User(name='ed', fullname='Ed Jones', nickname='edsnickname')>]
2019-02-16 21:45:23,931 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname
FROM users
WHERE users.id <= ?
2019-02-16 21:45:23,931 INFO sqlalchemy.engine.base.Engine (5,)
[<User(name='ed', fullname='Ed Jones', nickname='edsnickname')>, <User(name='wendy', fullname='Wendy Williams', nickname='windy')>, <User(name='mary', fullname='Mary Contrary', nickname='mary')>]
2019-02-16 21:45:23,932 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=? WHERE users.id = ?
2019-02-16 21:45:23,932 INFO sqlalchemy.engine.base.Engine ('admin', 1)
2019-02-16 21:45:23,933 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
2019-02-16 21:45:23,933 INFO sqlalchemy.engine.base.Engine ('fred', 'Fred Flintstone', 'freddy')
2019-02-16 21:45:23,934 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=? WHERE users.id = ?
2019-02-16 21:45:23,934 INFO sqlalchemy.engine.base.Engine ('test', 2)
2019-02-16 21:45:23,935 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, users.nickname AS users_nickname
FROM users
WHERE users.id <= ?
2019-02-16 21:45:23,935 INFO sqlalchemy.engine.base.Engine (5,)
[<User(name='admin', fullname='Ed Jones', nickname='edsnickname')>, <User(name='test', fullname='Wendy Williams', nickname='windy')>, <User(name='mary', fullname='Mary Contrary', nickname='mary')>, <User(name='fred', fullname='Fred Flintstone', nickname='freddy')>]

由于我们设置 create_engine 中 echo 为 True,因此在执行结果中包含了 SQLAlchemy 打印的 SQL 语句,我们可以取消 crete_engine 中的 echo

engine = create_engine('sqlite:///./sqlalchemy.sqlite')

此时的执行结果如下:

[<User(name='ed', fullname='Ed Jones', nickname='edsnickname')>]
[<User(name='ed', fullname='Ed Jones', nickname='edsnickname')>, <User(name='wendy', fullname='Wendy Williams', nickname='windy')>, <User(name='mary', fullname='Mary Contrary', nickname='mary')>]
[<User(name='admin', fullname='Ed Jones', nickname='edsnickname')>, <User(name='test', fullname='Wendy Williams', nickname='windy')>, <User(name='mary', fullname='Mary Contrary', nickname='mary')>, <User(name='fred', fullname='Fred Flintstone', nickname='freddy')>]

当取消 echo 后,程序运行结果中原有的 SQL 语句消失。

本文只是对 SQLAlchemy 的使用进行简单的介绍,SQLAlchemy 本身还有很多特性和运用方法我们可以共同探讨。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python连接mysql数据库示例(做增删改操作)
Dec 31 Python
使用Python编写vim插件的简单示例
Apr 17 Python
Python Sqlite3以字典形式返回查询结果的实现方法
Oct 03 Python
win10系统下Anaconda3安装配置方法图文教程
Sep 19 Python
scrapy-redis的安装部署步骤讲解
Feb 27 Python
python定时按日期备份MySQL数据并压缩
Apr 19 Python
python面向对象实现名片管理系统文件版
Apr 26 Python
python实现知乎高颜值图片爬取
Aug 12 Python
python实现猜数游戏
Mar 27 Python
从python读取sql的实例方法
Jul 21 Python
详解python tkinter包获取本地绝对路径(以获取图片并展示)
Sep 04 Python
Python使用for生成列表实现过程解析
Sep 22 Python
Python列表常见操作详解(获取,增加,删除,修改,排序等)
Feb 18 #Python
Python File(文件) 方法整理
Feb 18 #Python
Python异常处理知识点总结
Feb 18 #Python
Python os.access()用法实例
Feb 18 #Python
python使用pipeline批量读写redis的方法
Feb 18 #Python
Python变量类型知识点总结
Feb 18 #Python
Python中文编码知识点
Feb 18 #Python
You might like
利用php实现禁用IE和火狐的缓存问题
2012/12/03 PHP
PHP函数分享之curl方式取得数据、模拟登陆、POST数据
2014/06/04 PHP
php使用array_search函数实现数组查找的方法
2015/06/12 PHP
PHP查找一列有序数组是否包含某值的方法
2020/02/07 PHP
Firefox div高度自适应
2009/04/28 Javascript
详细讲解JS节点知识
2010/01/31 Javascript
JavaScript类型转换方法及需要注意的问题小结(挺全面)
2010/11/11 Javascript
js 分页全选或反选标识实现代码
2011/08/09 Javascript
JQuery动画和停止动画实例代码
2013/03/01 Javascript
js 操作符汇总
2014/11/08 Javascript
Javascript核心读书有感之类型、值和变量
2015/02/11 Javascript
深入理解JavaScript系列(41):设计模式之模板方法详解
2015/03/04 Javascript
基于JavaScript实现TAB标签效果
2016/01/12 Javascript
浅谈js中子页面父页面方法 变量相互调用
2016/08/04 Javascript
javascript使用闭包模拟对象的私有属性和方法
2016/10/05 Javascript
深入理解JavaScript中的块级作用域、私有变量与模块模式
2016/10/31 Javascript
JS常见简单正则表达式验证功能小结【手机,地址,企业税号,金额,身份证等】
2017/01/22 Javascript
Python求两个文本文件以行为单位的交集、并集与差集的方法
2015/06/17 Python
浅谈python编译pyc工程--导包问题解决
2019/03/20 Python
对PyQt5基本窗口控件 QMainWindow的使用详解
2019/06/19 Python
PyCharm搭建Spark开发环境的实现步骤
2019/09/05 Python
利用Python产生加密表和解密表的实现方法
2019/10/15 Python
基于python cut和qcut的用法及区别详解
2019/11/22 Python
计算pytorch标准化(Normalize)所需要数据集的均值和方差实例
2020/01/15 Python
opencv python图像梯度实例详解
2020/02/04 Python
W Concept美国:精选全球独立设计师
2017/02/22 全球购物
世界首屈一指的在线男士内衣权威:HisRoom
2017/08/05 全球购物
巴西最大的珠宝连锁店:Vivara
2019/04/18 全球购物
Ooni英国官网:披萨烤箱
2020/05/31 全球购物
JSF面试题:Jsf中的核心类用那些?有什么作用?LiftCycle六大生命周期是什么?
2014/07/17 面试题
上班玩手机检讨书
2014/02/17 职场文书
学习党的群众路线教育实践活动心得体会
2014/03/01 职场文书
党支部创先争优承诺书
2014/08/30 职场文书
实名检举信范文
2015/03/02 职场文书
个人专业技术总结
2015/03/05 职场文书
MySQL 数据丢失排查案例
2021/05/08 MySQL