ORM sqlachemy学习
内容:
1.ORM介绍
2.SQLAlchemy介绍
3.SQLAlchemy内部处理
4.SQLAlchemy使用
参考:
http://www.cnblogs.com/wupeiqi/articles/5713330.html
http://www.cnblogs.com/alex3714/articles/5978329.html
1.ORM介绍
ORM(object relational mapping),就是对象映射关系,简单来说:
对于python而已一切皆对象,但是我们使用的数据库却都是关系型的,为了保证一致的使用习惯,通过ORM将编程语言的对象模型和数据库的关系模型建立映射关系,这样我们在使用编程语言对数据库进行操作的时候可以直接使用编程语言的对象模型(类和对象)进行操作就可以了,而不用直接使用sql语言。
ORM优点:
- 隐藏了数据访问细节,“封闭”的通用数据库交互,使开发更方便快捷(数据库交互更简单)
- ORM使我们构造固化数据结构变得简单易行
ORM缺点:
无可避免的,自动化意味着映射和关联管理,代价是牺牲性能(早期,这是所有不喜欢ORM人的共同点)
现在各种ORM框架都在尝试使用各种方法来减轻这块(LazyLoad,Cache),效果还是很显著的。
2.SQLAlchemy介绍
(1)什么是SQLAlchemy
SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。
(2)SQLAlchemy原理
数据库表是一个二维表,包含多行多列。把一个表的内容用Python的数据结构表示出来的话,可以用一个list表示多行,list的每一个元素是tuple,表示一行记录,比如,包含id
和name
的user
表:
[
('', 'woz'),
('', 'wyb'),
('', 'alex')
]
Python的DB-API返回的数据结构就是像上面这样表示的,但是用tuple表示一行很难看出表的结构。
如果把一个tuple用class实例来表示,就可以更容易地看出表的结构来:
class User(object):
def __init__(self, id, name):
self.id = id
self.name = name [
User('', 'wyb'),
User('', 'woz'),
User('', 'alex')
]
这就是传说中的ORM技术:Object-Relational Mapping,就是把关系数据库的表结构映射到类的对象上
但是由谁来做这个转换呢?由专业的ORM框架来做转换,Python中最有名的ORM框架是SQLAlchemy
(3)安装
pip3 install SQLAlchemy
3.SQLAlchemy内部处理
(1)依赖第三方
SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如:
MySQL-Python (py2语法)
mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname> pymysql (py3语法)
mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>] MySQL-Connector
mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname> cx_Oracle
oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...] 更多详见:http://docs.sqlalchemy.org/en/latest/dialects/index.html
(2)内部处理
使用 Engine/ConnectionPooling/Dialect 进行数据库操作,Engine使用ConnectionPooling连接数据库,然后再通过Dialect执行SQL语句
4.SQLAlchemy使用
SQLAlchemy的使用本质上就是对其ORM功能的使用,详细说就是使用 ORM/Schema Type/SQL Expression Language/Engine/ConnectionPooling/Dialect 所有组件对数据进行操作。根据类创建对象,对象转换成SQL,执行SQL
(1)创建表
创建一个表(user)并插入数据:
# __author__ = "wyb"
# date: 2018/8/20
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import (
create_engine,
Column,
Integer,
String,
) # create_engine类似pymysql中的connect
# 设置echo将打印一系列过程信息
engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/wyb",
encoding="utf-8",
echo=True,
max_overflow=5) Base = declarative_base() # 生成ORM基类 # 接下来创建一个User表
class User(Base):
__tablename__ = 'user' # 表名
id = Column(Integer, primary_key=True)
name = Column(String(32))
password = Column(String(64)) Base.metadata.create_all(engine) # 创建表结构 # 接下来对表中数据进行操作
# 创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
Session_class = sessionmaker(bind=engine)
Session = Session_class() # 生成session实例(类似pymysql中的cursor) # 生成数据对象(未创建,commit之后才创建)
user_obj = User(name="wyb", password="")
user_obj2 = User(name="woz", password="")
Session.add(user_obj) # 把数据对象添加到session里, 后面统一创建
Session.add(user_obj2) # 把数据对象添加到session里, 后面统一创建
Session.commit() # 现此统一提交,创建数据
(2)操作表(增删改查)
# __author__ = "wyb"
# date: 2018/8/20
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import (
create_engine,
Column,
Integer,
String,
) # create_engine类似pymysql中的connect
# 设置echo将打印一系列过程信息
engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/wyb",
encoding="utf-8",
# echo=True,
max_overflow=5) Base = declarative_base() # 生成ORM基类
Session_class = sessionmaker(bind=engine) # 创建session类
Session = Session_class() # 生成session实例(类似pymysql中的cursor) # 接下来创建一个User表
class User(Base):
__tablename__ = 'user' # 表名
id = Column(Integer, primary_key=True)
name = Column(String(32))
password = Column(String(64)) # 直接输出查询结果
# __repr__是魔法方法 当直接输出User对象的实例会调用此方法
def __repr__(self):
return "<User(id='%s', name='%s', password='%s')>" % (
self.id, self.name, self.password) # 创建表结构
def create_table():
Base.metadata.create_all(engine) # 插入
def insert(user_obj):
print("插入数据:")
print(user_obj)
Session.add(user_obj) # 把数据对象添加到session里, 后面统一创建
Session.commit() # 现此统一提交,创建数据 # 查找
def select():
print("查询数据:") # 查询一条数据:
data = Session.query(User).filter_by(name="woz").first() # 不存在返回None
print("name=woz: ", data)
data = Session.query(User).filter_by(id=1).first()
print("id=1: ", data)
# print(my_user.id, my_user.name, my_user.password) # 输出具体值 # 查询所有数据:
print("表中所有数据: ", Session.query(User.id, User.name).all()) # 多条件查询:
objs = Session.query(User).filter(User.id > 0).filter(User.id < 3).all()
# 上面2个filter的关系相当于 user.id >1 AND user.id <3 的效果
print("id为0到3之间的数据: ", objs) # 删除
def delete():
print("删除数据:")
result = Session.query(User).filter(User.name == 'alex').first()
print(result)
Session.delete(result)
Session.commit() # 更新
def update():
print("更新数据:")
my_user = Session.query(User).filter_by(name="wyb").first()
my_user.name = "wyb666"
my_user.password = "wyb666"
print(my_user)
Session.commit() # 主程序
def main():
create_table()
# 插入数据:
# insert(User(name="alex", password="3373"))
# 查询数据:
# select()
# update()
# delete() if __name__ == '__main__':
main()
(3)回滚以及统计分组
回滚:
my_user = Session.query(User).filter_by(id=1).first()
my_user.name = "Jack" fake_user = User(name='Rain', password='')
Session.add(fake_user) print(Session.query(User).filter(User.name.in_(['Jack','rain'])).all() ) # 这时看session里有你刚添加和修改的数据
Session.rollback() #此时你rollback一下
print(Session.query(User).filter(User.name.in_(['Jack','rain'])).all() ) # 再查就发现刚才添加的数据没有了。 # Session.commit()
统计分组:
# 统计:
Session.query(User).filter(User.name.like("w%")).count() # 分组
from sqlalchemy import func
print(Session.query(func.count(User.name),User.name).group_by(User.name).all() )
# 相当于以下原生SQL:
SELECT count(user.name) AS count_1, user.name AS user_name
FROM user GROUP BY user.name
(4)外键关联
外键关联:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy import (
create_engine,
Column,
Integer,
String,
ForeignKey,
) engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/wyb",
encoding="utf-8",
max_overflow=5) Base = declarative_base() # 生成ORM基类
Session_class = sessionmaker(bind=engine) # 创建session类
Session = Session_class() # 生成session实例(类似pymysql中的cursor) # User表
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(32))
password = Column(String(64)) def __repr__(self):
return "<User(id='%s', name='%s', password='%s')>" % (
self.id, self.name, self.password) # Address表
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email_address = Column(String(32), nullable=False)
user_id = Column(Integer, ForeignKey('user.id')) # 这是外键 user = relationship("User", backref="address") # 这个nb,允许你在user表里通过backref字段反向查出所有它在addresses表里的关联项 def __repr__(self):
return "<Address(email_address='%s')>" % self.email_address # 创建表结构
def create_table():
Base.metadata.create_all(engine)
上述表创建好后,可以这样反查:
1 objs = Session.query(User).all()
add_objs = Session.query(Address).all()
for i in objs: # 通过遍历user对象反查关联的address记录
print(i.address)
for add_obj in add_objs: # 遍历add_objs里直接查关联的user对象
print(add_obj.user.name)
创建关联对象:
obj = Session.query(User).filter(User.name == 'woz').first()
# 查询关联对象的属性:
print(obj.address)
# 添加关联对象:
obj.address = [Address(email_address="wyb@126.com")]
Session.commit()
多外键关联:
下表中,Customer表有2个字段都关联了Address表
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
street = Column(String)
city = Column(String)
state = Column(String) class Customer(Base):
__tablename__ = 'customer'
id = Column(Integer, primary_key=True)
name = Column(String) billing_address_id = Column(Integer, ForeignKey("address.id"))
shipping_address_id = Column(Integer, ForeignKey("address.id")) # 这样写 会导致SQLAlchemy分不清哪个外键是对应哪个字段 会导致程序报错
# billing_address = relationship("Address")
# shipping_address = relationship("Address") # 所以要这样写:
billing_address = relationship("Address", foreign_keys=[billing_address_id])
shipping_address = relationship("Address", foreign_keys=[shipping_address_id])
(5)多对多联系
什么是多对多联系:学生和课程,一个课程可以有多个学生,一个学生可以有多个课程
如下所示:
# 多对多
# 一个学生可以有多个课程,一个课程可以对应多个学生
student_m2m_course = Table('student_m2m_course', Base.metadata,
Column('student_id', Integer, ForeignKey('student.id')),
Column('author_id', Integer, ForeignKey('course.id')),
) # 学生类
class Student(Base):
__tablename__ = 'student'
id = Column(Integer, primary_key=True)
name = Column(String(64))
attach = relationship('Attach', secondary=student_m2m_course, backref='students') def __repr__(self):
return "<name: %s;>" % self.name # 课程类
class Course(Base):
__tablename__ = 'course'
id = Column(Integer, primary_key=True)
name = Column(String(32)) def __repr__(self):
return "<name: %s;>" % self.name
具体操作:
# 关联插入
a1 = Student(name="12342ds")
a2 = Student(name="")
a3 = Student(name="") b1 = Course(name="跟wyb学Python")
b2 = Course(name="跟wyb学把妹")
b3 = Course(name="跟wyb学装逼")
b4 = Course(name="跟wyb学开车") a1.courses = [b1, b2]
a2.courses = [b2, b3]
a3.courses = [b1, b3] Session.add_all([a1, a2, a3, b1, b2, b3, b4])
Session.commit() # 多对多删除
# 删除数据时不用管student_m2m_course这个表, sqlalchemy会自动帮你把对应的数据删除
student_obj = Session.query(Student).filter_by(name="12342ds").first() course_obj = Session.query(Course).filter_by(name="跟wyb学把妹").first()
print(student_obj, course_obj)
# 以下是两种删除方法:
student_obj.courses.remove(course_obj) # 从课程中里删除一个学生
Session.delete(course_obj ) # 直接删除课程时会把这个课程和所有学生的关联关系删除
Session.commit()
(6)其他
处理中文:
sqlalchemy设置编码字符集一定要在数据库访问的URL上增加charset=utf8,否则数据库的连接就不是utf8的编码格式
eng = create_engine('mysql://root:root@localhost:3306/test2?charset=utf8',echo=True)
最后内容 - 今日作业:
主题:学员管理系统
需求:
- 用户角色,讲师\学员, 用户登陆后根据角色不同,能做的事情不同,分别如下
- 讲师视图
- 管理班级,可创建班级,根据学员qq号把学员加入班级
- 可创建指定班级的上课纪录,注意一节上课纪录对应多条学员的上课纪录, 即每节课都有整班学员上, 为了纪录每位学员的学习成绩,需在创建每节上课纪录是,同时 为这个班的每位学员创建一条上课纪录
- 为学员批改成绩, 一条一条的手动修改成绩
- 学员视图
- 提交作业
- 查看作业成绩
- 一个学员可以同时属于多个班级,就像报了Linux的同时也可以报名Python一样, 所以提交作业时需先选择班级,再选择具体上课的节数
- 附加:学员可以查看自己的班级成绩排名
ORM sqlachemy学习的更多相关文章
- Python之路-python(mysql介绍和安装、pymysql、ORM sqlachemy)
本节内容 1.数据库介绍 2.mysql管理 3.mysql数据类型 4.常用mysql命令 创建数据库 外键 增删改查表 5.事务 6.索引 7.python 操作mysql 8.ORM sqlac ...
- ORM sqlachemy
本节内容 ORM介绍 sqlalchemy安装 sqlalchemy基本使用 多外键关联 多对多关系 表结构设计作业 1. ORM介绍 orm英文全称object relational mapping ...
- ORM PHP 学习记录
ORM:object relation mapping,即对象关系映射,简单的说就是对象模型和关系模型的一种映射.为什么要有这么一个映射?很简单,因为现在的开发语言基本都是oop的,但是传统的数据库却 ...
- ORM框架学习之EF
首先推荐一篇很好的EF文章翻译,可以系统的学习一遍. <Entity Framework 6 Recipes>中文翻译系列 EF使用体会 优点: 可以省去Ado.net复杂的管道连接代码. ...
- python中orm框架学习
安装sqlalchemy pip3 install sqlalchemy 创建表结构: from sqlalchemy import Column,String,create_engine from ...
- 转:C#制作ORM映射学习笔记三 ORM映射实现
现在开始实现ORM的主体模块,首先需要在项目中新建一个类,命名为DbAccess,然后在项目的引用中添加两个dll,分别是MySql.Data.dll和System.Data.SQLite.dll,这 ...
- 转:C#制作ORM映射学习笔记二 配置类及Sql语句生成类
在正式开始实现ORM之前还有一点准备工作需要完成,第一是实现一个配置类,这个很简单的就是通过静态变量来保存数据库的一些连接信息,等同于.net项目中的web.config的功能:第二需要设计实现一个s ...
- 转:C#制作ORM映射学习笔记一 自定义Attribute类
之前在做unity项目时发现只能用odbc连接数据库,感觉非常的麻烦,因为之前做web开发的时候用惯了ORM映射,所以我想在unity中也用一下ORM(虽然我知道出于性能的考虑这样做事不好的,不过自己 ...
- SqlSugar ORM 的学习
http://www.codeisbug.com/Doc/8/1163 https://www.cnblogs.com/sunkaixuan/p/6082664.html
随机推荐
- Linux服务器没有GUI的情况下使用matplotlib绘图
最近看到关于 python3 中用matplotlib 不进行交互画图,而是直接将图保存到硬盘,主要的一个设置就是 matplotlib.use('agg') 注明: 其实不设置 matplotl ...
- I.MX6 make menuconfig OTG to slave only mode
/****************************************************************************** * I.MX6 make menucon ...
- VC++ 6.0 C8051F340 USB PC侧通信 Demo
// HelloWorld.cpp : Defines the entry point for the console application. // /*********************** ...
- Intellij导入插件工程,不能运行(需要EditConfiguration)
https://blog.csdn.net/wjskeepmaking/article/details/78815896 可以作为参考 这里要说的一点是,如果项目被识别为plugin,那么就应该在项目 ...
- 【c++基础】判断是否到文件末尾-eof函数
前言 读取文件内容时,需要判断是否到文件末尾,此时用到eof函数. 函数定义 Check whether eofbit is set Returns true if theeofbiterror st ...
- opencv-原图基础上添加指定颜色
前言 项目中需要将某些区域使用不同的颜色表示出来,同时能够看到原图作为底色. 代码 #include "opencv2/highgui/highgui.hpp" #include ...
- 在 Windows 10 中开启移动 WLAN 热点
本文将介绍如何在 Windows 10 中开启移动 Wi-Fi 热点. This post is written in multiple languages. Please select yours: ...
- 黑电-逻辑地址-0X4EB9FDE3- %o %d %x
****************************************************************************** 编程语言通常规定是以0开头的数字是八进制数 ...
- BMP、GIF、JPEG、PNG以及其它图片格式简单介绍
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/songjinshi/article/details/37516649 BMP格式 BMP是英文Bit ...
- tomcat catalina.out切割脚本
shell脚本catalina.out 切割脚本...每天23.30切割.删除七天之前的日志这里3个tomcat实例(1)拷贝日志文件(2)清空日志文件*只能清空如果删除tomcat不重启不会生成新的 ...