SQLAlchemy 教程 —— 基础入门篇
SQLAlchemy 教程 —— 基础入门篇
一、课程简介
1.1 实验内容
本课程带领大家使用 SQLAlchemy 连接 MySQL 数据库,创建一个博客应用所需要的数据表,并介绍了使用 SQLAlchemy 进行简单了 CURD 操作及使用 Faker 生成测试数据。
1.2课程知识点
- 学会用 SQLALchemy 连接数据库(MySQL, SQLite, PostgreSQL), 创建数据表;
- 掌握表数据之间一对一,一对多及多对多的关系并能转化为对应 SQLAlchemy 描述;
- 掌握使用 SQLAlchemy 进行 CURD 操作;
- 学会使用 Faker 生成测试数据
学习本课程需要你对 Python 与 MySQL 都有基本的掌握。
二、ORM 与 SQLAlchemy 简介
ORM 全称 Object Relational Mapping
, 翻译过来叫对象关系映射
。简单的说,ORM 将数据库中的表与面向对象语言中的类建立了一种对应关系。这样,我们要操作数据库,数据库中的表或者表中的一条记录就可以直接通过操作类或者类实例来完成。
SQLAlchemy 是Python 社区最知名的 ORM 工具之一,为高效和高性能的数据库访问设计,实现了完整的企业级持久模型。
接下来我们将使用 SQLAlchemy 和 MySQL 构建一个博客应用的实验库。
先安装 SQLAlchemy:
$ sudo pip install sqlalchemy
三、连接与创建
实验楼环境已经为我们安装了 MySQL,但还没有启动, 在启动 MySQL 之前,我们需要进行一些配置,将 MySQL 默认的 latin1 编码改成 utf8 。
$ sudo vim /etc/mysql/my.cnf
通过上面的命令打开 MySQL 的配置文件, 添加下面几个配置:
[client]
default-character-set = utf8
[mysqld]
character-set-server = utf8
[mysql]
default-character-set = utf8
保存退出。现在我们可以启动 MySQL 服务了:
$ sudo service mysql start
在命令行下输入下面命令启动 MySQL:
$ mysql -uroot -p
看到上面的内容就说明我们的 MySQL 可以正常启动了(注意,上面的密码不需要输入内容,直接回车就行), 并且我们我们通过命令:
> create database blog;
创建一个名为 blog
的数据库为下面的使用作准备。
另外,我们需要安装一个 Python 与 MySQL 之间的驱动程序:
$ sudo apt-get install python-mysqldb
3.1 连接数据库
我们在 Code 下新建个 Python 文件,叫什么名字就随你便了,这里我们叫 db.py
,写入下面的内容:
# coding: utf-8
from sqlalchemy import create_engine
engine = create_engine('mysql+mysqldb://root@localhost:3306/blog')
print(engine)
在上面的程序中,我们连接了默认运行在 3306
端口的 MySQL 中的 blog
数据库。
运行下这个程序,看到下面的信息说明我们已经连接成功了:
3.2 描述表结构
要使用 ORM, 我们需要将数据表的结构用 ORM 的语言描述出来。SQLAlchmey 提供了一套 Declarative 系统来完成这个任务。我们以创建一个 users
表为例,看看它是怎么用 SQLAlchemy 的语言来描述的:
# coding: utf-8
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String, Integer
engine = create_engine('mysql+mysqldb://root@localhost:3306/blog?charset=utf8')
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(64), nullable=False, index=True)
password = Column(String(64), nullable=False)
email = Column(String(64), nullable=False, index=True)
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.username)
我们看到,在 User
类中,用 __tablename__
指定在 MySQL 中表的名字。我们创建了三个基本字段,类中的每一个 Column
代表数据库中的一列,在 Colunm
中,指定该列的一些配置。第一个字段代表类的数据类型,上面我们使用 String
, Integer
俩个最常用的类型,其他常用的包括:
Text
Boolean
SmallInteger
DateTime
nullable=False
代表这一列不可以为空,index=True
表示在该列创建索引。
另外定义 __repr__
是为了方便调试,你可以不定义,也可以定义的更详细一些。
$ python db.py
运行程序,我们在 MySQL 中看看表是如何创建的:
四、关系定义
4.1 一对多关系
对于一个普通的博客应用来说,用户和文章显然是一个一对多的关系,一篇文章属于一个用户,一个用户可以写很多篇文章,那么他们之间的关系可以这样定义:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(64), nullable=False, index=True)
password = Column(String(64), nullable=False)
email = Column(String(64), nullable=False, index=True)
articles = relationship('Article')
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.username)
class Article(Base):
__tablename__ = 'articles'
id = Column(Integer, primary_key=True)
title = Column(String(255), nullable=False, index=True)
content = Column(Text)
user_id = Column(Integer, ForeignKey('users.id'))
author = relationship('User')
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.title)
每篇文章有一个外键指向 users
表中的主键 id
, 而在 User
中使用 SQLAlchemy 提供的 relationship
描述 关系。而用户与文章的之间的这个关系是双向的,所以我们看到上面的两张表中都定义了 relationship
。
SQLAlchemy 提供了 backref
让我们可以只需要定义一个关系:
articles = relationship('Article', backref='author')
添加了这个就可以不用再在 Article
中定义 relationship
了!
4.2 一对一关系
在 User
中我们只定义了几个必须的字段, 但通常用户还有很多其他信息,但这些信息可能不是必须填写的,我们可以把它们放到另一张 UserInfo
表中,这样User
和 UserInfo
就形成了一对一的关系。你可能会奇怪一对一关系为什么不在一对多关系前面?那是因为一对一关系是基于一对多定义的:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(64), nullable=False, index=True)
password = Column(String(64), nullable=False)
email = Column(String(64), nullable=False, index=True)
articles = relationship('Article', backref='author')
userinfo = relationship('UserInfo', backref='user', uselist=False)
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.username)
class UserInfo(Base):
__tablename__ = 'userinfos'
id = Column(Integer, primary_key=True)
name = Column(String(64))
qq = Column(String(11))
phone = Column(String(11))
link = Column(String(64))
user_id = Column(Integer, ForeignKey('users.id'))
定义方法和一对多相同,只是需要添加 userlist=False
。
4.3 多对多关系
一遍博客通常有一个分类,好几个标签。标签与博客之间就是一个多对多的关系。多对多关系不能直接定义,需要分解成俩个一对多的关系,为此,需要一张额外的表来协助完成:
article_tag = Table(
'article_tag', Base.metadata,
Column('article_id', Integer, ForeignKey('articles.id')),
Column('tag_id', Integer, ForeignKey('tags.id'))
)
class Tag(Base):
__tablename__ = 'tags'
id = Column(Integer, primary_key=True)
name = Column(String(64), nullable=False, index=True)
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.name)
4.4 映射到数据
表已经描述好了,在文件末尾使用下面的命令在我们连接的数据库中创建对应的表:
if __name__ == '__main__':
Base.metadata.create_all(engine)
进入 MySQL 看看:
所有的表都已经创建好了!
五、简单 CURD
当你想打电话给朋友时,你是否得用手机拨通他的号码才能建立起一个会话?同样的,你想和 MySQL 交谈也得先通过 SQLAlchemy 建立一个会话:
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
你可以把 sessionmaker
想象成一个手机,engine
当做 MySQL 的号码,拨通这个“号码”我们就创建了一个 Session 类,下面就可以通过这个类的实例与 MySQL 愉快的交谈了!
5.1 Create
如果你玩过LOL, 我想你一定知道Faker。而在 Python的世界中,Faker 是用来生成虚假数据的库。 安装它:
$ sudo pip install faker
下面结合 Faker 库创建一些测试数据:
faker = Factory.create()
Session = sessionmaker(bind=engine)
session = Session()
faker_users = [User(
username=faker.name(),
password=faker.word(),
email=faker.email(),
) for i in range(10)]
session.add_all(faker_users)
faker_categories = [Category(name=faker.word()) for i in range(5)]
session.add_all(faker_categories)
faker_tags= [Tag(name=faker.word()) for i in range(20)]
session.add_all(faker_tags)
for i in range(100):
article = Article(
title=faker.sentence(),
content=' '.join(faker.sentences(nb=random.randint(10, 20))),
author=random.choice(faker_users),
category=random.choice(faker_categories)
)
for tag in random.sample(faker_tags, random.randint(2, 5)):
article.tags.append(tag)
session.add(article)
session.commit()
在上面的代码中我们创建了10个用户,5个分类,20个标签,100篇文章,并且为每篇文章随机选择了2~5个标签。
使用 SQLAlchemy 往数据库中添加数据,我们只需要创建相关类的实例,调用 session.add()
添加一个,或者 session.add_all()
一次添加多个, 最后 session.commit()
就可以了。
5.2 Retrieve
如果我们知道用户 id,就可以用 get
方法, filter_by
用于按某一个字段过滤,而 filter
可以让我们按多个字段过滤,all
则是获取所有。
获取某一字段值可以直接类的属性获取:
5.3 Update
更新一个字段:
>>> a = session.query(Article).get(10)
>>> a.title = 'My test blog post'
>>> session.add(a)
>>> session.commit()
添加一个标签:
>>> a = session.query(Article).get(10)
>>> a.tags.append(Tag(name='python'))
>>> session.add(a)
>>> session.commit()
5.4 Delete
>>> a = session.query(Article).get(10)
>>> session.delete(a)
>>> session.commit()
删除直接调用 delete
删除获取到的对象,提交 session 即可。
完整代码
# coding: utf-8
import random
from faker import Factory
from sqlalchemy import create_engine, Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import ForeignKey
from sqlalchemy import Column, String, Integer, Text
from sqlalchemy.orm import sessionmaker, relationship
engine = create_engine('mysql+mysqldb://root@localhost:3306/blog?charset=utf8')
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(64), nullable=False, index=True)
password = Column(String(64), nullable=False)
email = Column(String(64), nullable=False, index=True)
articles = relationship('Article', backref='author')
userinfo = relationship('UserInfo', backref='user', uselist=False)
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.username)
class UserInfo(Base):
__tablename__ = 'userinfos'
id = Column(Integer, primary_key=True)
name = Column(String(64))
qq = Column(String(11))
phone = Column(String(11))
link = Column(String(64))
user_id = Column(Integer, ForeignKey('users.id'))
class Article(Base):
__tablename__ = 'articles'
id = Column(Integer, primary_key=True)
title = Column(String(255), nullable=False, index=True)
content = Column(Text)
user_id = Column(Integer, ForeignKey('users.id'))
cate_id = Column(Integer, ForeignKey('categories.id'))
tags = relationship('Tag', secondary='article_tag', backref='articles')
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.title)
class Category(Base):
__tablename__ = 'categories'
id = Column(Integer, primary_key=True)
name = Column(String(64), nullable=False, index=True)
articles = relationship('Article', backref='category')
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.name)
article_tag = Table(
'article_tag', Base.metadata,
Column('article_id', Integer, ForeignKey('articles.id')),
Column('tag_id', Integer, ForeignKey('tags.id'))
)
class Tag(Base):
__tablename__ = 'tags'
id = Column(Integer, primary_key=True)
name = Column(String(64), nullable=False, index=True)
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.name)
if __name__ == '__main__':
Base.metadata.create_all(engine)
faker = Factory.create()
Session = sessionmaker(bind=engine)
session = Session()
faker_users = [User(
username=faker.name(),
password=faker.word(),
email=faker.email(),
) for i in range(10)]
session.add_all(faker_users)
faker_categories = [Category(name=faker.word()) for i in range(5)]
session.add_all(faker_categories)
faker_tags= [Tag(name=faker.word()) for i in range(20)]
session.add_all(faker_tags)
for i in range(100):
article = Article(
title=faker.sentence(),
content=' '.join(faker.sentences(nb=random.randint(10, 20))),
author=random.choice(faker_users),
category=random.choice(faker_categories)
)
for tag in random.sample(faker_tags, random.randint(2, 5)):
article.tags.append(tag)
session.add(article)
session.commit()
六、总结与习题
本篇教程带领大家使用 SQLAlchemy 创建了一个博客应用的数据库及相关表,再次过程中, 介绍了使用 SQLAlchemy 定义一对一、一对多及多对多关系,CURD 及使用 Faker 生成测试数据。
习题
现在博客应用需要添加评论功能,使用 SQLAlchemy 创建一张评论表, 并使用 Faker 为每篇文章生成几条测试评论。
SQLAlchemy 教程 —— 基础入门篇的更多相关文章
- Linux及Arm-Linux程序开发笔记(零基础入门篇)
Linux及Arm-Linux程序开发笔记(零基础入门篇) 作者:一点一滴的Beer http://beer.cnblogs.com/ 本文地址:http://www.cnblogs.com/bee ...
- 【Linux开发】Linux及Arm-Linux程序开发笔记(零基础入门篇)
Linux及Arm-Linux程序开发笔记(零基础入门篇) 作者:一点一滴的Beer http://beer.cnblogs.com/ 本文地址:http://www.cnblogs.com/beer ...
- BAT脚本编写教程简单入门篇
BAT脚本编写教程简单入门篇 批处理文件最常用的几个命令: echo表示显示此命令后的字符 echo on 表示在此语句后所有运行的命令都显示命令行本身 echo off 表示在此语句后所有运行的命 ...
- Xamarin XAML语言教程基础语法篇大学霸
Xamarin XAML语言教程基础语法篇大学霸 前 言 Xamarin是一个跨平台开发框架.它可以用来开发iOS.Android.Windows Phone和Mac的应用程序.使用Xamarin框 ...
- FPGA基础入门篇(四) 边沿检测电路
FPGA基础入门篇(四)--边沿检测电路 一.边沿检测 边沿检测,就是检测输入信号,或者FPGA内部逻辑信号的跳变,即上升沿或者下降沿的检测.在检测到所需要的边沿后产生一个高电平的脉冲.这在FPGA电 ...
- JS基础入门篇(三十五)—面向对象(二)
如果没有面向对象这种抽象概念的小伙伴,建议先看一下我写的JS基础入门篇(三十四)-面向对象(一)
- 云小课|DGC数据开发之基础入门篇
阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要:欢迎来到DGC数据 ...
- Elasticsearch 7.x 之文档、索引和 REST API 【基础入门篇】
前几天写过一篇<Elasticsearch 7.x 最详细安装及配置>,今天继续最新版基础入门内容.这一篇简单总结了 Elasticsearch 7.x 之文档.索引和 REST API. ...
- .NET ORM 的 “SOD蜜”--零基础入门篇
PDF.NET SOD框架不仅仅是一个ORM,但是它的ORM功能是独具特色的,我在博客中已经多次介绍,但都是原理性的,可能不少初学的朋友还是觉得复杂,其实,SOD的ORM是很简单的.下面我们就采用流行 ...
随机推荐
- Tomcat下使用Druid配置JNDI数据源
com.alibaba.druid.pool.DruidDataSourceFactory实现了javax.naming.spi.ObjectFactory,可以作为JNDI数据源来配置. 一.下载D ...
- ubuntu安装latex
1 终端中输入"sudo apt-get install texlive-full",输入root密码. 若不想安装所有文件,可以选择"sudo apt-get inst ...
- RobotFramework自动化测试框架的基础关键字(三)
1.1.1 如何定义一个字典 此处我们说的字典,其实就等同于python语言中的字典,和列表一样,字典也是python语言中非常常用的一种数据结构,也类似于Java 语言中的Map. 在 ...
- Keras官方中文文档:Keras安装和配置指南(Windows)
这里需要说明一下,笔者不建议在Windows环境下进行深度学习的研究,一方面是因为Windows所对应的框架搭建的依赖过多,社区设定不完全:另一方面,Linux系统下对显卡支持.内存释放以及存储空间调 ...
- 【洛谷2015】【CJOJ1976】二叉苹果树
题面 Description 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1.我们用一根树枝两端连 ...
- C#中的函数式编程:序言(一)
学了那么久的函数式编程语言,一直想写一些相关的文章.经过一段时间的考虑,我决定开这个坑. 至于为什么选择C#,在我看来,编程语言分三类:一类是难以进行函数式编程的语言,这类语言包括Java6.C语言等 ...
- 前端综合学习笔记---异步、ES6/7、Module、Promise同步 vs 异步
同步 vs 异步 先看下面的 demo,根据程序阅读起来表达的意思,应该是先打印100,1秒钟之后打印200,最后打印300.但是实际运行根本不是那么回事 console.log(100) setTi ...
- IT连创业系列:新的一年,先淫文一篇!
办公室窗外,有鸟声〜〜 在IT连创业走过的日子里,这是我第一次听见鸟声. 也许,是曾经的忙碌,封锁了自己的心眼. 岁月秒秒: 当初燃烧的火焰,从红,烧成了蓝. 曾经的内心湃澎,化成了平淡坚持. 但这, ...
- oracle 裸设备划分 --centos6.5
主题思想:物理卷PV->卷组VG->逻辑卷LV(类型:raw)->添加表空间 操作过程 vg_orcl 8g 一:划分 二:创建裸设备 方法1:目前最常用的方法 #c ...
- wcf类库及宿主
说起wcf,一直以来总是直接创建wpf的应用程序,这样默认的宿主是IIS.如果想更换宿主,那么我们首先得创建wcf类库. 这个类库会自动创建一个app.config文件.到最后部署的时候,把它移到宿主 ...