ORM 全称 Object Relational Mapping, 翻译过来叫对象关系映射。简单的说,ORM 将数据库中的表与面向对象语言中的类建立了一种对应关系。这样,我们要操作数据库,数据库中的表或者表中的一条记录就可以直接通过操作类或者类实例来完成。
SQLAlchemy 是Python 社区最知名的 ORM 工具之一,为高效和高性能的数据库访问设计,实现了完整的企业级持久模型。
安装
sudo apt-get update
sudo pip3 install sqlalchemy
连接与创建
首先我们需要将MySQL默认的编码改为utf-8
sudo vim /etc/mysql/my.cnf
添加配置
[client]
default-character-set = utf8
[mysqld]
character-set-server = utf8
[mysql]
default-character-set = utf8
保存退出
我们启动MySQL并安装一个python与MySQL的驱动程序
sudo pip3 install pymysql
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
# dialect+driver://username:password@host:port/database
# dialect [ˈdaɪəlekt] 就是指DBMS(数据库管理系统)的名称,一般可选的值有:postgresql, mysql, sqlite等
# driver就是指驱动的名称,如果不指定,SQLAlchemy会使用默认值。database就是指DBMS中的一个数据库
# create_engine函数还支持以下几个参数:
# connect_args:一个字典,用来自定义数据库连接的参数,比如指定客户端使用的字符编码。
# pool_size和max_overflow:指定连接池的大小。
# poolclass:指定连接池的实现
# echo:一个布尔值,用来指定是否打印执行的SQL语句到日志中。
# 一般来说,Engine对象会默认启用连接池
# 应用程序可以调用Engine对象的connect()方法来获得一个到数据库的连接对象;
# 然后可以在这个连接对象上调用execute()来执行SQL语句,调用begin()、commit()、rollback()来执行事务操作;
# 调用close()来关闭连接。Engine对象也有一些快捷方法来直接执行上述操作,
# 避免了每次都要调用connect()来获取连接这种繁琐的代码,比如engine.execute(), with engine.begin()等。
#
engine = create_engine('mysql+pymysql://root:[email protected]:3306/pydb?charset=utf8')
# 定义数据模型
# 有了数据库连接后,我们就可以来定义数据模型了,也就是定义映射数据库表的Python类。在SQLAlchemy中,
# 这是通过Declarative的系统来完成的
# 要使用Declarative系统,你需要为所有映射类创建一个基类,这个基类用来维护所有映射类的元信息
Base = declarative_base()
# 定义映射类 这里的基类Base是上面我们通过declarative_base函数生成的
# 这个类的__table__属性就保存了该映射类所映射的Table对象
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 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 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定义映射类
# 创建所有的表。我们告诉create_all使用哪个engine,它就会生成所有的CREATE TABLE语句,并且通过engine发送到数据库上执行
Base.metadata.create_all(engine)
# faker是一个Python包,为您生成你所需要的任何(假)数据。
# 实例化
faker = Factory.create()
# 会话(session)是我们通过SQLAlchemy来操作数据库的入口。我们前面有介绍过SQLAlchemy的架构,session是属于ORM层的。
# Session的功能是管理我们的程序和数据库之间的会话,它利用Engine的连接管理功能来实现会话。
# 我们在上文有提到,我们创建了Engine对象,但是一般不直接使用它,而是把它交给ORM去使用。
# 其中,通过session来使用Engine就是一个常用的方式。
# 要是用session,我们需要先通过sessionmaker函数创建一个session类,然后通过这个类的实例来使用会话
# 我们通过sessionmaker的bind参数把Engine对象传递给DBSession去管理。
# 然后,DBSession实例化的对象session就能被我们使用了
Session = sessionmaker(bind=engine)
session = Session()
# 随机生成10个user的list
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()
# CRUD
# CRUD就是CREATE, READ, UPDATE, DELETE,增删改查。这个也是SQLAlchemy中最常用的功能,而且都是通过上一小节中的session对象来使用的。
# 我们这简单的介绍一下这四个操作,后面会给出官方文档的位置。
# Create
# 在数据库中插入一条记录,是通过session的add()方法来实现的,你需要先创建一个映射类的实例,然后调用session.add()方法,
# 然后调用session.commit()方法提交你的事务(关于事务,我们下面会专门讲解):
# new_person = Person(name='new person')
# session.add(new_person)
# session.commit()
# Delete
# 删除操作和创建操作差不多,是把一个映射类实例传递给session.delete()方法。
#
# Update
# 更新一条记录需要先使用查询操作获得一条记录对应的对象,然后修改对象的属性,再通过session.add()方法来完成更新操作。
#
# Read
# 查询操作,一般称为query,在SQLAlchemy中一般是通过Query对象来完成的。我们可以通过session.query()方法来创建一个Query对象,
# 然后调用Query对象的众多方法来完成查询操作。
#
# 事务
# 使用session,就会涉及到事务,我们的应用程序也会有很多事务操作的要求。当你调用一个session的方法,导致session执行一条SQL语句时,
# 它会自动开始一个事务,直到你下次调用session.commit()或者session.rollback(),它就会结束这个事务。
# 你也可以显示的调用session.begin()来开始一个事务,并且session.begin()还可以配合Python的with来使用。
# python中最假的库——faker
# fake.city() # 城市名称
# fake.street_name() # 街道名称
# fake.country_code() # 国家编号
# fake.longitude() # 经度
# fake.address() # 地址
# fake.latitude() # 纬度
# fake.street_address() # 街道地址
# fake.city_suffix() # 市
# fake.postcode() # 邮政编码
# fake.country() # 国家
# fake.street_suffix() # 街道后缀
# fake.building_number() # 建筑编号
# fake.license_plate() # 车牌号
# fake.rgb_css_color() #颜色RGB
# fake.safe_color_name() # 颜色名称
# fake.company() # 公司名
# fake.credit_card_number(card_type=None) # 信用卡卡号
# fake.date_time(tzinfo=None) # 随机日期时间
# fake.file_extension(category=None) # 文件扩展信息
# fake.ipv4(network=False) # ipv4地址
其他参考文档:
https://segmentfault.com/a/1190000004261891