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 复制这段内容后 ...
随机推荐
- 编译android的一些坑
1 降级gcc g++到4.4 2 参考:http://source.android.com/source/initializing.html来配置环境 3 使用jdk1.6 包括 java java ...
- H264--2--语法及结构[5]
名词解释 场和帧 : 视频的一场或一帧可用来产生一个编码图像.在电视中,为减少大面积闪烁现象,把一帧分成两个隔行的场. 片: 每个图象中,若干宏块被排列成片的形式.片分为 ...
- Tensorflow学习笔记——张量、图、常量、变量(一)
1 张量和图 TensorFlow是一种采用数据流图(data flow graphs),用于数值计算的开源软件库.其中 Tensor 代表传递的数据为张量(多维数组),Flow 代表使用计算图进行运 ...
- 前端性能调优Gzip Filter
转自:https://blog.csdn.net/zxk15982106569/article/details/18922613 客户端向web服务器端发出了请求后,通常情况下服务器端会将页面文件和其 ...
- C#面向过程之类型转换、算术运算符、关系运算符、逻辑运算符、if-else语句、switch-case、循环结构(while、for)、三元表达式
数据类型转换: int.parse()只能转换string类型的 当参数为null时会报异常int i =Convert.ToInt32(false) 运行结果是0int i =Convert.ToI ...
- sql2000数据库置疑造成的原因以及如何解决置疑
造成数据库置疑一般有以下几点: 1)电脑非法关机或者意外停电: 2)磁盘有坏道或者损坏: 3)数据库感染病毒,日志文件损坏: 4)非正常情况下移动数据库文件 5)系统,硬盘,经常强制性关机(如断电)类 ...
- bzoj 1828: [Usaco2010 Mar]balloc 农场分配【贪心+线段树】
长得挺唬人的贪心,按照右端点排序,用最小值线段树的询问判断当前牛是否能放进去,能的话更新线段树,ans++ 来自https://www.cnblogs.com/rausen/p/4529245.htm ...
- jQuery插件之jqzoom的使用和参数设置
jqzoom是一款基于jQuery的图片方法插件. 使用方法:1.引入jQuery与jqzoom,jqzoom.css 2.准备两张一大一小大小相同的图片,小图片放在<img>标签的&qu ...
- python使用ddt模块对用例执行操作
import time import unittest import ddt from selenium import webdriver TEST_URL = "http://www.ba ...
- 对mysql修改库里面所有的引擎mysaim 为 innodb
1.查看当前数据引擎的命令: show engines; 2. USE `[DBNAME]`; SELECT GROUP_CONCAT(CONCAT( 'ALTER TABLE ' ,TABLE_NA ...