Object-Relational Mapping,作用是将关系型数据库的表结构映射到对象上,使我们可以不必关心具体的SQL语句进行数据库的增删改查操作。

缺点是映射操作不可避免的会有性能上的损耗,优点是不必考虑SQL,程序与数据库的交互被封装,可以快速地开发。

sqlalchemy是Python中最著名的ORM框架。

sqlalchemy连接数据库

sqlalchemy支持主流的数据库,连接不同的数据库需要安装不同的组件
1.连接mysql(mariadb)
sqlalchemy默认使用mysql-python作为链接驱动,既default模式
选哪种驱动,就装哪个包。
#default默认链接方式
engine = create_engine('mysql://scott:tiger@localhost/foo')
# mysql-python,声明使用mysql-python驱动
engine = create_engine('mysql+mysqldb://scott:tiger@localhost/foo')
#MySQL-connector-python 声明使用MySQL-connector-python驱动(推荐使用)
engine = create_engine('mysql+mysqlconnector://scott:tiger@localhost/foo')
#OurSQL 声明使用OurSQL驱动
engine = create_engine('mysql+oursql://scott:tiger@localhost/foo')

2.连接Microsoft SQL Server
sqlalchemy默认使用 pyodbc作为链接驱动。
#pyodbc
engine = create_engine('mssql+pyodbc://scott:tiger@mydsn')
#pymssql
engine = create_engine('mssql+pymssql://scott:tiger@hostname:port/dbname')

3.连接PostgreSQL
PostgreSQL默认使用 psycopg2作为链接驱动,既default模式
#default
engine = create_engine('postgresql://scott:tiger@localhost/mydatabase')
#psycopg2
engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/mydatabase')
#pg8000
engine = create_engine('postgresql+pg8000://scott:tiger@localhost/mydatabase')

4.连接Oracle
Oracle可能只有 cx_oracle一个驱动包,既default模式和声明模式一样。
#default
engine = create_engine('oracle://scott:tiger@127.0.0.1:1521/sidname')
#cx_oracle
engine = create_engine('oracle+cx_oracle://scott:tiger@tnsname')

使用sqlalchemy创建数据库中表的映射

sqlalchemy创建映射的方法有两种:

1.定义一个类通过这个类来映射表结构

from sqlalchemy.orm import sessionmaker
#映射类的基类
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.engine import create_engine
from sqlalchemy import Column,Integer,String"""
定义一个类,用来映射数据库中的表
该类的基类通过declarative_base()获得
"""
Base = declarative_base()
class Customer(Base):__tablename__ = "customer"id = Column(Integer,primary_key=True)name = Column(String(32))age = Column(Integer)#用于打印对象时的输出def __repr__(self):return "id:%d name:%s age:%d" %(self.id,self.name,self.age)

2.通过Table创建映射

from sqlalchemy import MetaData,Table,Column,String,Integer
from sqlalchemy import create_engine
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy.orm import mapper"""
通过MetaData创建数据库表的表结构,这种创建方法一般用于不需要对该表手动进行操作的情况,
例如连接多张表的中间表
"""
metadata = MetaData()
customer = Table("customer",metadata,Column("id",Integer,primary_key=True),Column("name",String(32)),Column("age",Integer))"""
定义一个字段与表一一对应的普通类,注意此时继承的是object
"""
class Customer(object):def __init__(self,id,name,age):self.id=idself.name=nameself.age=age#用于打印对象时的输出def __repr__(self):return "id:%d name:%s age:%d" %(self.id,self.name,self.age)"""
通过mapper建立表结构与类的映射
"""
mapper(Customer, customer)

  

常见的表约束关系

class Customer(Base):__tablename__ = "customer"#primary_key 主键,默认identity(1,1)id = Column(Integer,primary_key=True,autoincrement=False)#创建自增列 identity(100,1),注意一个表只能有一个自增列auto_id = Column(Integer,Sequence("auto_id_seq",start=100,increment=1))#唯一键约束unique_id = Column(Integer,unique=True)#联合唯一unique_name = Column(String(32))unique_address = Column(String(32))#建立联合唯一约束__table_args__ = (UniqueConstraint("unique_name","unique_address"),)

  

增删改查

1.前置工作,创建表结构映射关系

from sqlalchemy import Column,Integer,String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy import or_,and_engine = create_engine('mssql+pyodbc://python:123456@mydb',echo=False)session_class = sessionmaker(bind=engine)
session = session_class()Base =declarative_base()"""
定义表结构
"""
class Student(Base):__tablename__ = "student""""sqlalchemy默认定义为主键便是自增的,可以用autoincrement手动指定"""id = Column(Integer,primary_key=True)name = Column(String(32),nullable=False)grade_and_class = Column(String(32),nullable=False)age = Column(Integer,nullable=False)def __repr__(self):return "%d %s %s" %(self.id,self.name,self.grade_and_class)

使用sqlalchemy进行数据库的增删改查操作都是基于上面定义的映射关系

2.创建表

Base.metadata.create_all(engine)

定义好映射关系之后执行create_all操作,会循环继承自Base的所有类,如果数据库中不存在同名的表,那么orm便会根据类中的定义创建一张新的表。如果已经存在同名的表则直接pass

3.删除表

Base.metadata.drop_all(engine)

定义好映射关系之后执行drop_all操作,会循环继承自Base的所有类并将其从数据库中删除

4.添加记录

obj = Student(name="马克",grade_and_class="202",age=19)
session.add(obj)
obj = Student(name="Mike",grade_and_class="102",age=18)
session.add(obj)obj1 = Student(name="Jack",grade_and_class="202",age=18)
obj2 = Student(name="Tom",grade_and_class="202",age=18)
session.add_all([obj1,obj2])
#add只是将对象添加到session之中,必须执行commit才会提交到数据库session.commit()

5.删除记录

objs =session.query(Student).filter(Student.name=="Pinkman").delete()

或者

objs =session.query(Student).filter(Student.name=="Pinkman")
for obj in objs:session.delete(obj)

6.修改记录

方法一:

"""
修改数据
"""
objs = session.query(Student).filter(Student.name=="Tom").all()
for obj in objs:obj.name = "Pinkman"
session.commit()

直接在映射上进行修改,session进行commit之后就会反映到数据库中。

方法二:

使用update

session.query(Student).filter(Student.name=="Tom").update({Student.name=="Pinkman"})

  

6.回滚

session操作的时候相当于自动开启了一个begin,在commit之前可以任意回滚

session.query(Student).delete()
session.rollback()
session.query(Student).filter(Student.name == "Mike").delete()
session.commit()

7.查询

"""
filter与filter_by的传入参数格式有区别,其他的一样
以下四种查询限定条件的写法结果完全一样
查询不用执行commit,因为对数据库并没有修改
"""
objs = session.query(Student).filter(Student.grade_and_class=="202",Student.age==18).all()
print(objs)
objs = session.query(Student).filter_by(grade_and_class="202",age=18).all()
print(objs)
objs = session.query(Student).filter(Student.grade_and_class == "202").filter(Student.age == 18).all()
print(objs)
objs = session.query(Student).filter_by(grade_and_class="202").filter_by(age=18).all()
print(objs)

like:

objs = session.query(Student).filter(Student.name.like("%i%"))

in:

objs = session.query(Student).filter(Student.age.in_([18,20]))

not in:

objs = session.query(Student).filter(~Student.age.in_([18,20]))

or:

objs = session.query(Student).filter(or_(Student.age==18,Student.name=="马克"))

and:

objs = session.query(Student).filter(and_(Student.age==18,Student.name=="马克"))

分组函数:

#所有的分组函数都定义在func中
objs1 = session.query(Student.name,func.sum(Student.age)).group_by(Student.name).all()objs2 = session.query(Student.name,func.count(Student.name)).group_by(Student.name).all()

打印行号row_number:

session.query(over(func.row_number(),order_by=(Member.id)).label("row_num"),Member).all()

8.多表联合查询

定义一个用户表member和一个用户角色表role,member通过role_id和role的id做连接。

如果没有建立外键约束或者不在映射中定义虚拟连接对象,可以使用多表联合查询进行查询。

cross join:

objs = session.query(Member,Role).filter(Member.role_id==Role.id).all()

inner join:

query中的第一个表为内连接左表,join中的表为内连接右表。

objs = session.query(Member,Role).join(Role,Role.id == Member.role_id).all()

outer join:

outjoin是左外链接,没有单独的右外连接,有需求的话直接将两个表反过来(小表左连接右表效率高)

objs = session.query(Member,Role).outerjoin(Role,Role.id == Member.role_id).all()

排序

对字段进行排序有多种方法:

1.使用order_by

#排序方法一
#正序
res = session.query(Member).order_by(Member.role_id).all()
#逆序一,使用desc方法
# res = session.query(Member).order_by(desc(Member.role_id)).all()
#逆序二,在排序列前面加上"-"
# res = session.query(Member).order_by(-Member.role_id).all()
for item in res:print(item.role_id)#排序方法二:使用字符串,注意此时如果要指定表名的话必须使用数据库表名
res = session.query(Member).order_by("role_id").all()
# res = session.query(Member).order_by("role_id desc").all()
# res = session.query(Member).order_by("-role_id").all()
for item in res:print(item.role_id)

2.直接在定义映射时使用__mapper_args__设置排序

class Member(Base):__tablename__ = "member_demo"id = Column(Integer,primary_key=True)name = Column(String(32),nullable=False)role_id = Column(Integer)def __repr__(self):return "%s %s %s" %(self.id,self.name,self.role_id)#定义默认的排序__mapper_args__ = {"order_by":role_id.desc()}

在__mpper_args__中定义了order_by之后,orm查询出来的数据就会默认排序,可以调用order_by()来改变排序顺序

外键关联

定义如下两张表,以id进行外键关联,注意外键关联的字段必须是主键或者是unique

"""
商品信息表goods:
id(编号,主键)
name(名称,非空)
place_of_origin_id(产地id,非空)
产地信息表origin:
id(编号,主键)
name(名称,非空)
"""

定义映射:

class Goods(Base):__tablename__ = "goods_demo"id = Column(Integer,primary_key=True)name = Column(String(32),nullable=False)#创建外键place_of_origin_id = Column(Integer,ForeignKey("origin_demo.id"),nullable=False)#创建一个虚拟关系,通过该字段可以直接访问关联的外键表,而外键表也可以使用backref定义的字段来反向查询主表信息origin = relationship("Origin",backref="goods")def __repr__(self):return "[%s]产地[%s]" %(self.name,self.origin.name)class Origin(Base):__tablename__ = "origin_demo"id = Column(Integer,primary_key=True)name = Column(String(32),nullable=False)def __repr__(self):return "%d:%s" %(self.id,self.name)engine = create_engine('mssql+pyodbc://python:123456@mydb',echo=False)
#建表
Base.metadata.create_all(engine)

维护外键的时候,如果在relationship中定义了backref的话,那么外键表通过该字段便可以直接反查与自己相关的引用表的数据

#引用外键的表可以通过定义的relationship访问关联的外键表数据
print("from goods to origin")
goods = session.query(Goods).filter(Goods.name == "英国的故事").all()
for item in goods:print(item.origin)#外键表可以通过引用外键表中relationship中定义的backref反向查询与自己有关联的表的数据
print("from origin to goods")
origins = session.query(Origin).all()
for origin in origins:print(origin.goods)

多外键关联

普通的多外键语法与单外键完全一样,但如果一张表的多个字段应用了同一张表的同一个字段作为外键的话,必须在relationship中显示的声明外键对应的字段,否则在插入数据的时候程序无法区分会报错

class Mail(Base):__tablename__ = "Mail_demo"id = Column(Integer,primary_key=True)addr_id1 = Column(Integer,ForeignKey("address_demo.id"),nullable=False)addr_id2 = Column(Integer,ForeignKey("address_demo.id"),nullable=False)addr1 = relationship("Address",foreign_keys=[addr_id1])addr2 = relationship("Address",foreign_keys=[addr_id2])

多对多的表结构 

如果两个事物之间存在一种多对多的关系,比如一本书可能有一个以上的作者,而一个作者又可能写过一本以上的书,此时要维护两者之间的关系,一般会将这种关系抽离出来作为一个单独的表,加上单纯的书本信息表,作者信息表,三者构成一个多对多的数据库关系。

"""
图书信息表book
id
name
作者信息表author
id
name
图书作者关系表relation_book_author
book_id
author_id
图书信息和作者信息是多对多的关系,对应关系由关系表维护"""

定义三个表的映射:

#中间表
relation_book_author = Table("relation_book_author_demo",Base.metadata,Column("book_id",Integer,ForeignKey("book_demo.id")),Column("author_id",Integer,ForeignKey("author_demo.id")))class Book(Base):__tablename__ = "book_demo"id = Column(Integer,primary_key=True)name = Column(String(32),nullable=False)authors = relationship("Author",secondary=relation_book_author,backref="books")def __repr__(self):return self.nameclass Author(Base):__tablename__ = "author_demo"id = Column(Integer,primary_key=True)name = Column(String(32),nullable=False)def __repr__(self):return self.name

添加数据

book1 = Book(name="算法导论")
book2 = Book(name="计算机系统")
book3 = Book(name="Linux基础")
book4 = Book(name="Python的前世今生")author1 = Author(name="谢尔曼")
author2 = Author(name="肖恩")
author3 = Author(name="曼宁")
author4 = Author(name="凯夫拉")book1.authors = [author1]
book2.authors = [author1,author2]
book3.authors = [author2,author3,author1]
book4.authors = [author2,author3]#如果只是add所有的book的话,那么和book有关联信息的authoe也会一并提交
#注意,提交到数据库的顺序并不一定就是程序写的顺序,relation表中的id也许会和程序中的顺序不一样
session.add_all([book1,book2,book3,book4,author1,author2,author3,author4])
session.commit()

上面的代码没有直接对图书作者关系信息表进行操作,相关的操作都是orm为我们自动执行的

查询:

obj_book = session.query(Book).filter(Book.name == "Linux基础").all()
print("Linux基础的作者".center(30,"-"))
for item in obj_book:print(item.authors)obj_author = session.query(Author).filter(Author.name == "肖恩").all()
print("肖恩写的书".center(30,"-"))
for item in obj_author:print(item.books)

结果

----------Linux基础的作者----------
[肖恩, 谢尔曼, 曼宁]
------------肖恩写的书-------------
[计算机系统, Linux基础, Python的前世今生]

同样的,直接删除Book和Author映射对象之后,orm也会为我们自动清理relation_book_author表中对应的数据。

直接删除书
obj_book = session.query(Book).filter(Book.name == "算法导论").all()
for item in obj_book:session.delete(item)session.commit()删除某本书的一个作者
obj_book = session.query(Book).filter(Book.name == "Linux基础").first()
obj_author = session.query(Author).filter(Author.name == "肖恩").first()if obj_author in obj_book.authors:obj_book.authors.remove(obj_author)session.commit()

子查询

使用subquery可以生成一个临时表,可对该表进行一系列的查询、连接操作

tmp=session.query(Member.name,func.sum(Member.role_id).label("sum")).group_by(Member.name).subquery()
res = session.query(tmp.c.sum).all()

注意引用临时表的列名时在表名和列名之间有一个c

转载于:https://www.cnblogs.com/Hexdecimal/p/9460997.html

Python入门学习笔记17(sqlalchemyd的使用)相关推荐

  1. Python入门学习笔记1-Python基础

    Python入门学习笔记1-Python基础 前言:本文介绍了Python学习的前导知识概念以及必记基础函数,如善用help方法查看帮助文档,以及内置对象类型的概念以及常用函数的详解. 一.Pytho ...

  2. Python入门学习笔记

    1 Python入门教程 2 Hello, world! 3 Python中的数据类型 4 可迭代对象 4.1 tuple和list 4.2 set和dict 4.3 range() 4.4 切片 5 ...

  3. 零基础Python入门学习笔记(持续更新)

    编译器:Pycharm 库安装: 快捷键Ctrl+Alt+S 点击项目->Python解释器点加号搜索库名称 常见问题: debug无法使用 卸载重新安装对应版本的Python 符号快查: 转义 ...

  4. Python入门学习笔记(7)

    今日学习内容为高级字符串内置函数. 1.eval()函数 --执行一个字符串表达式并返回执行结果 语法格式: eval(expression[,globals[,locals]]) expressio ...

  5. Python入门学习笔记(6)

    在医院关了一周的禁闭,终于出关了,Python学习继续!今日学习字符串的常规操作(fighting!!) 1.1 拼接字符串 用 " + "拼接字符串 字符串和其他类型数据无法直接 ...

  6. Python入门学习笔记(5)

    今日周末安排的学习内容比较简单是元组. 元组和列表结构相似,区别在于元组中的元素不可以单独修改,二列表中的元素可以任意修改. 1.元组的创建和删除 使用赋值运算符创建 num = (1,2,7,9,1 ...

  7. Python入门学习笔记(4)

    今天学习序列和列表. 1.序列 在python中,序列结构主要有列表.元组.集合.字典和字符串.对于这些序列通常会有如下操作: 1.1索引 序列中的每一个元素都有一个编号,称之为索引,是从0开始递增的 ...

  8. Python入门学习笔记(3)

    今日学习语句,在程序设计中的3种基本结构是顺序结构.选择结构和循环结构. 1.顺序结构语句 顺序结构语句就是按照程序语句的自然顺序,从上到下,一次执行每条语句的程序,这是程序中最基础的语句,赋值语句. ...

  9. Python入门学习笔记(2)

    今日学习数据类型和基本运算符. 1. 保留字和标识符 1.1保留字 保留字是Python已经被赋予特定意义的一些单词,在开发程序时,不可以把这些保留字作为变量.函数.类.模块和其他对象的名称来使用.P ...

最新文章

  1. Deep Learning 目标检测
  2. WebStorm错误--无法显示文件夹目录
  3. LINUX防火墙打开与关闭
  4. 计算机系统基础期中考试,计算机系统基础第二次作业.docx
  5. 代码执行-preg_replace
  6. datatable 创建列赋值_DataTable创建行和列,DataReader读取
  7. java实现文件压缩与解压
  8. 今天参加广州.NET俱乐部活动,运气超好
  9. CSS盒模型层次平面示意图和3D示意图
  10. 易语言查询Windows API之网络函数消息函数
  11. 北京科技大学计算机博士统考,北京科技大学计算机与通信工程学院2016年博士录取方案...
  12. mysql中查看虚拟环境_进程、虚拟环境、mysql
  13. 机器学习中的核方法(Kernel Method)
  14. 使用cmake生成.so动态库
  15. 网页HTML5制作flex布局骰子,css利用flex布局画骰子的六个面
  16. 【转载】三十而已,信智依然 | 田溯宁:写在亚信科技30华诞
  17. shell in find exclude
  18. 开源CRM+SaaS云服务的生态模式能否撬动中国管理软件市场?
  19. 计算机原理随堂练答案,计算机原理随堂练习(第二章)
  20. 遗忘线代知识,导致应力第三不变量对应力的导数求不出来

热门文章

  1. clickhouse集群容器化搭建
  2. Python学习笔记--day15 内置模块和开发规范
  3. leaflet 导出图片,打印图片(A4横版或竖版)
  4. 【转】程序员面试揭秘之程序员靠什么途径去美国工作?
  5. 通过宽高自适应设计两栏布局和三栏布局
  6. 祝愿大家未来顺利平安
  7. bundle包是什么意思_bundle与package区别与联系
  8. jsjsjsjsjssjsjsjs
  9. 在Win32中使用OpenGL
  10. 1553B通信项目开发笔记(四)bu61580程序编写,实现回环之RT端