Python orm基础
ORM 对象映射关系程序。
通过orm将编程语言的对象模型和数据库的关系模型建立映射关系,这样我们在使用编程语言对数据库进行操作的时候可以直接使用编程语言的对象模型进行操作就可以了,而不用直接使用sql语言。
orm的优点:
- 隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得我们的通用数据库交互变得简单易行,并且完全不用考虑该死的SQL语句。快速开发,由此而来。
- ORM使我们构造固化数据结构变得简单易行。
缺点:
- 无可避免的,自动化意味着映射和关联管理,代价是牺牲性能(早期,这是所有不喜欢ORM人的共同点)。现在的各种ORM框架都在尝试使用各种方法来减轻这块(LazyLoad,Cache),效果还是很显著的。
最有名的ORM框架是SQLAlchemy,系统中没有该模块的需要安装 pip install sqlalchemy (或easy_install SQLAlchemy)
如果在pip install sqlalchemy 中报ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org'错,需要先设置超时时间:pip --default-timeout=100 install -U Pillow,再重新安装 pip install sqlalchemy,通过imort sqlalchemy验证是否安装正常。
ORM框架SQLAlchemy 使用,创建表:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#conding:utf-8import sqlalchemyfrom sqlalchemy import create_enginefrom sqlalchemy.ext.declarative import declarative_basefrom sqlalchemy import Column,Integer,String #区分大小写#创建连接engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True)#生成orm基类base=declarative_base()class user(base): __tablename__ = 'users' #表名 id = Column(Integer, primary_key=True) name = Column(String(32)) password = Column(String(64))base.metadata.create_all(engine) #创建表结构 |
注:pymysql设置编码字符集一定要在数据库访问的URL上增加?charset=utf8,否则数据库的连接就不是utf8的编码格式
|
1
|
engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True) |
ORM框架SQLAlchemy 使用,插入数据:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#conding:utf-8import sqlalchemyfrom sqlalchemy import create_enginefrom sqlalchemy.ext.declarative import declarative_basefrom sqlalchemy import Column,Integer,String #区分大小写from sqlalchemy.orm import sessionmaker#创建连接engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True)#生成orm基类base=declarative_base()class user(base): __tablename__ = 'users' #表名 id = Column(Integer, primary_key=True) name = Column(String(32)) password = Column(String(64))base.metadata.create_all(engine) #创建表结构Session_class=sessionmaker(bind=engine) ##创建与数据库的会话,class,不是实例Session=Session_class() #生成session实例user_obj = user(name="rr",password="123456") #插入你要创建的数据对象,每执行一次都会新增一次数据。print user_obj.name,user_obj.id #此时还没创建对象呢,不信你打印一下id发现还是NoneSession.add(user_obj) #把要创建的数据对象添加到这个session里print user_obj.name,user_obj.id #此时也依然还没创建Session.commit() #提交,使前面修改的数据生效。 |
结果:

查询:
|
1
2
3
|
my_user = Session.query(user).filter_by(name="ee").first() #创建查询对象print(my_user.id,my_user.name,my_user.password) #输出查询内容print my_user #内存地址 |
结果:

修改:
|
1
2
3
|
my_user = Session.query(user).filter_by(name="yy").first() #根据指定条件创建符合条件的对象my_user.name='uu' #将name='yy'的name修改为uuprint(my_user.id,my_user.name,my_user.password) #输出查询内容 |
结果:

参考数据表:

回滚:
|
1
2
3
4
5
6
7
|
user_obj = user(name="kk",password="99999") #插入你要创建的数据对象Session.add(user_obj) #把要创建的数据对象添加到这个session里my_user = Session.query(user).filter_by(name="rr").first() #根据指定条件创建符合条件的对象,first()是指name='rr'的第一条记录my_user.name="gg" #将name='yy'的name修改为uuprint(Session.query(user).filter(user.name.in_(["gg","kk"])).all()) #显示修改后的数据Session.rollback() #回滚print(Session.query(user).filter(user.name.in_(["gg","kk"])).all()) #显示回滚后的内容 |
结果:

获取所有数据
|
1
|
print Session.query(user.id,user.name).all() #只显示id,name |
结果:

多条件查询
|
1
2
|
objs = Session.query(user).filter(user.id>0).filter(user.id<=3).all() #注意:filter()中的关键字不能是表达式user.id=0print objs |
filter的关系相当于 user.id >0 AND user.id <=3 的效果
结果:

统计和分组
|
1
2
|
objs = Session.query(user).filter(user.name.like('r%')).count() #统计print objs |
结果:

|
1
2
|
from sqlalchemy import funcprint(Session.query(func.count(user.name),user.name).group_by(user.name).all() ) #分组 |
结果:

外键关联
参照表:两张表是一对多的关系。
|
1
|
users(一) |

addresses(多)

创建表addresses,将users表中的id作为addresses表的外键。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
import sqlalchemyfrom sqlalchemy import create_enginefrom sqlalchemy.ext.declarative import declarative_basefrom sqlalchemy import Column,Integer,String,ForeignKey #区分大小写from sqlalchemy.orm import sessionmaker,relationship#创建连接engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True)#生成orm基类base=declarative_base()class user(base): __tablename__ = 'users' #表名 id = Column(Integer, primary_key=True) name = Column(String(32)) password = Column(String(64)) def __repr__(self): return "<user(id='%d',name='%s', password='%s')>" % (self.id, self.name, self.password) class Address(base): __tablename__ = 'addresses' id = Column(Integer, primary_key=True) email_address = Column(String(32), nullable=False) user_id = Column(Integer, ForeignKey('users.id')) user = relationship("user", backref="addresses") '''允许你在user表里通过backref字段反向查出所有它在addresses表里的关联项,在内存中创建。在addresses表中可以使用user来查询users表中的数据,在users表中可以使用backref后的addresses来查询assresses表中的数据。''' def __repr__(self): return "<Address(email_address='%s',id='%d',user_id='%d')>" % (self.email_address,self.id,self.user_id)base.metadata.create_all(engine) #创建表结构Session_class=sessionmaker(bind=engine) #创建与数据库的会话,class,不是实例Session=Session_class() #生成session实例obj = Session.query(user).first()print obj.addresses #在users表里面通过addresses来查询addresses表中的数据。for i in obj.addresses: print i addr_obj = Session.query(Address).first()print(addr_obj.user) #在addresses表中通过user来查询users表中的数据。print(addr_obj.user.name)Session.commit() #提交,使前面修改的数据生效。 |
结果:

输出的结果1是列表形式,print 多行记录时以列表的形式显示。
注:在定义表的类下面加 def __repr__(self): return ... 是为了在print时输出哪些数据,以及输出后的显示形式。
补充:1.主键:是唯一标识一条记录,不能有重复的,不允许为空,用来保证数据完整性
2.外键:是另一表的主键, 外键可以有重复的, 可以是空值,用来和其他表建立联系用的。所以说,如果谈到了外键,一定是至少涉及到两张表。例如下面这两张表:

设定条件向指定表中添加记录:
|
1
2
3
4
5
|
obj = Session.query(user).filter(user.name=='ee').all()[0] #设定条件print(obj.addresses)obj.addresses = [Address(email_address="ertttt"), #向addresses表中添加2列。 Address(email_address="dddd")] |
结果:


多外键关联
在Customer表有2个字段都关联了Address表
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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")) '''#创建的列billing_address_id、shipping_address_id都作为外键关联address表中id列''' billing_address = relationship("Address") shipping_address = relationship("Address")#创建两个关联项 class Address(base): __tablename__ = 'address' id = Column(Integer, primary_key=True) street = Column(String) city = Column(String) state = Column(String) |
如果报错:
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join
condition between parent/child tables on relationshipCustomer.billing_address - there are multiple foreign key|
1
2
|
illing_address = relationship("Address", foreign_keys=[billing_address_id])shipping_address = relationship("Address", foreign_keys=[shipping_address_id]) |
使pymysql分清哪个外键是对应哪个字段。
多对多关系
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
from sqlalchemy import Table, Column, Integer,String,DATE, ForeignKeyfrom sqlalchemy.orm import relationshipfrom sqlalchemy.ext.declarative import declarative_basefrom sqlalchemy import create_enginefrom sqlalchemy.orm import sessionmakerengine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True)base = declarative_base()book_m2m_author = Table('book_m2m_author', base.metadata, Column('book_id',Integer,ForeignKey('books.id')), Column('author_id',Integer,ForeignKey('authors.id')), ) #创建book_m2m_author表,关联另外两张表。class Book(base): __tablename__ = 'books' id = Column(Integer,primary_key=True) name = Column(String(64)) pub_date = Column(DATE) authors = relationship('Author',secondary=book_m2m_author,backref='books') def __repr__(self): return self.nameclass Author(base): __tablename__ = 'authors' id = Column(Integer, primary_key=True) name = Column(String(32)) def __repr__(self): return self.namebase.metadata.create_all(engine) #创建表结构Session_class=sessionmaker(bind=engine) #创建与数据库的会话,class,不是实例Session=Session_class()b1 = Book(name="跟A学Python")b2 = Book(name="跟A学linux")b3 = Book(name="跟A学java")b4 = Book(name="跟C学开发") a1 = Author(name="A")a2 = Author(name="B")a3 = Author(name="C") b1.authors = [a1,a2] #建立关系b2.authors = [a1,a2,a3]Session.add_all([b1,b2,b3,b4,a1,a2,a3])Session.commit() |
结果:



用orm查一下数据
|
1
2
3
4
5
|
book_obj = Session.query(Book).filter_by(name="跟A学Python").first()print(book_obj.name, book_obj.authors)#这里book_obj.authors只输出name,因为定义类Author时在__repr__(self):定义了返回值 author_obj =Session.query(Author).filter_by(name="A").first()print(author_obj.name , author_obj.books) |
结果:


多对多删除
1.通过书删除作者,删除的是关系。
|
1
2
3
|
author_obj =Session.query(Author).filter_by(name="C").first()book_obj = Session.query(Book).filter_by(name="跟A学linux").first()book_obj.authors.remove(author_obj) #通过指定书里删除作者,删除的是关系,作者不受影响。 |
2.删除作者的同时也删除关系。
|
1
2
|
author_obj =Session.query(Author).filter_by(name="A").first()Session.delete(author_obj) #delete删除作者A,关系也会删除掉。 |
结果:
books表

|
1
|
authors表 |

book_m2m_author表

Python orm基础的更多相关文章
- Python文件基础
===========Python文件基础========= 写,先写在了IO buffer了,所以要及时保存 关闭.关闭会自动保存. file.close() 读取全部文件内容用read,读取一行用 ...
- 3.Python编程语言基础技术框架
3.Python编程语言基础技术框架 3.1查看数据项数据类型 type(name) 3.2查看数据项数据id id(name) 3.3对象引用 备注Python将所有数据存为内存对象 Python中 ...
- Python爬虫基础
前言 Python非常适合用来开发网页爬虫,理由如下: 1.抓取网页本身的接口 相比与其他静态编程语言,如java,c#,c++,python抓取网页文档的接口更简洁:相比其他动态脚本语言,如perl ...
- 小白必看Python视频基础教程
Python的排名从去年开始就借助人工智能持续上升,现在它已经成为了第一名.Python的火热,也带动了工程师们的就业热.可能你也想通过学习加入这个炙手可热的行业,可以看看Python视频基础教程,小 ...
- python/ORM操作详解
一.python/ORM操作详解 ===================增==================== models.UserInfo.objects.create(title='alex ...
- Python爬虫基础之requests
一.随时随地爬取一个网页下来 怎么爬取网页?对网站开发了解的都知道,浏览器访问Url向服务器发送请求,服务器响应浏览器请求并返回一堆HTML信息,其中包括html标签,css样式,js脚本等.我们之前 ...
- 零基础学Python--------第2章 Python语言基础
第2章 Python语言基础 2.1 Python语法特点 2.11注释 在Python中,通常包括3种类型的注释,分别是单行注释.多行注释和中文编码声明注释. 1.单行注释 在Python中,使用 ...
- Python学习基础笔记(全)
换博客了,还是csdn好一些. Python学习基础笔记 1.Python学习-linux下Python3的安装 2.Python学习-数据类型.运算符.条件语句 3.Python学习-循环语句 4. ...
- Python数据分析基础教程
Python数据分析基础教程(第2版)(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1_FsReTBCaL_PzKhM0o6l0g 提取码:nkhw 复制这段内容后 ...
随机推荐
- 第一个GraphX程序
程序功能:收集顶点指向的邻居中所在地 /* * 找出每一个顶点所指向的邻居中所在的地区 */ import org.apache.spark.SparkContext import org.apach ...
- [git push] rejecteded 问题的解决方法
错误信息: hint: Updates were rejected because a pushed branch tip is behind its remote hint: counterpart ...
- [计算机]如何在win7下查看并更改文件的默认后缀名
如何在win7下查看默认文件的后缀名并更改呢? 例如有一个文件本来是exe,想变更为txt.但是无法看到后缀名,就无法更改. 双击桌面上的计算机图标,或者任意盘符界面,单击如下图左侧“组织”右侧的下拉 ...
- 2016/2/24 . html . htm . shtml 的区别
htm.html.shtml网页区别 htm.html.shtml区别 接下来我们来了解下htm.shtml.html这三者之间区别.首先htm.html.shtml都是静态网页的后缀,三者也 ...
- Bing Maps进阶系列九:使用MapCruncher进行地图切片并集成进Bing Maps
Bing Maps进阶系列九:使用MapCruncher进行地图切片并集成进Bing Maps 在Bing Maps开发中,由于各种应用功能的不同,更多的时候用户可能需要将自己的一部分图片数据作为地图 ...
- 分享一个全开源的ASP.NET快速开发平台,能快速开发OA CRM ERP 等系统
bingo炸了 2017/3/30 16:28:14 阅读(870) 评论(0) 公司业务量比较大,接了很多项目,为了缩短开发周期老板让我牵头搭建了一个快速开发平台. 我们主要的业务是做OA.CRM. ...
- 杂项:MySQL
ylbtech-杂项:MySQL 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 0. https://www.mysql.com/ 1. https://bai ...
- git 删除本地仓库
更新: 2017/06/27 修改格式,备注mac下的命令没测试过 windows: rm .git/ mac: sudo rm -rf .git/ 没验证
- AutoCAD VBA添加菜单
# 给cad添加自定义菜单 Private Sub AddBar() Dim NewMenuItem As AcadPopupMenuItem Dim TheMacro As String Dim M ...
- 例题 3-5 谜题 uva227 Puzzle
A children’s puzzle that was popular years ago consisted of a × frame which contained small squares ...