python数据库操作orm_python【第十二篇下】操作MySQL数据库以及ORM之 sqlalchemy

内容一览:

1.Python操作MySQL数据库

2. ORM sqlachemy

2.1 ORM简介

对象关系映射(英语:Object Relation Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。

面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别。为了解决这个不匹配的现象,对象关系映射技术应运而生。

对象关系映射(Object-Relational Mapping)提供了概念性的、易于理解的模型化数据的方法。ORM方法论基于三个核心原则: 简单:以最基本的形式建模数据。 传达性:数据库结构被任何人都能理解的语言文档化。 精确性:基于数据模型创建正确标准化的结构。 典型地,建模者通过收集来自那些熟悉应用程序但不熟练的数据建模者的人的信息开发信息模型。建模者必须能够用非技术企业专家可以理解的术语在概念层次上与数据结构进行通讯。建模者也必须能以简单的单元分析信息,对样本数据进行处理。ORM专门被设计为改进这种联系。

简单的说:ORM相当于中继数据。

通过orm将编程语言的对象模型和数据库的关系模型建立映射关系,这样我们在使用编程语言对数据库进行操作的时候可以直接使用编程语言的对象模型进行操作就可以了,而不用直接使用sql语言。

986023-20161025094146281-759370126.png

orm的优点:

隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得我们的通用数据库交互变得简单易行,并且完全不用考虑该死的SQL语句。快速开发,由此而来。

ORM使我们构造固化数据结构变得简单易行。

缺点:

无可避免的,自动化意味着映射和关联管理,代价是牺牲性能(早期,这是所有不喜欢ORM人的共同点)。现在的各种ORM框架都在尝试使用各种方法来减轻这块(LazyLoad,Cache),效果还是很显著的。

2.2 sqlalchemy

在Python中,最有名的ORM框架是SQLAlchemy

(1)sqlalchemy的安装

pip install sqlalchemy

前提是安装了pymysql

(2)基本使用

SQL语句创建一个MySQL表是这样的:

1 CREATE TABLE user(2 id INTEGER NOT NULLAUTO_INCREMENT,3 name VARCHAR(32),4 password VARCHAR(64),5 PRIMARY KEY(id)6 )

这只是最简单的sql表,如果再加上外键关联什么的,一般程序员的脑容量是记不住那些sql语句的,于是有了orm,实现上面同样的功能,代码如下

1 #! /usr/bin/env python3

2 #-*- coding:utf-8 -*-

3

4 from sqlalchemy importcreate_engine5 from sqlalchemy.ext.declarative importdeclarative_base6 from sqlalchemy importColumn, Integer, String7

8 engine = create_engine("mysql+pymysql://root:Root-123@192.168.100.64/liuyouyuan?charset=utf8",echo=True)9

10 Base = declarative_base() #生成orm基类

11

12 classUser(Base):13 __tablename__ = 'user' #表名

14 id = Column(Integer, primary_key=True)15 name = Column(String(32))16 password = Column(String(64))17

18 Base.metadata.create_all(engine) #创建表结构

看了上面的代码是不是觉得更复杂了?这时你脑中有没有浮现黑格尔的那句“存在的就是合乎理性的。”?没有的话,你文盲。如果这个orm没毛用,就没有存在的必要了。且听我慢慢道来:

上面的创建表的方式还有一种,了解一下就行:

1 from sqlalchemy importTable, MetaData, Column, Integer, String, ForeignKey2 from sqlalchemy.orm importmapper3

4 metadata =MetaData()5

6 user = Table('user', metadata,7 Column('id', Integer, primary_key=True),8 Column('name', String(50)),9 Column('fullname', String(50)),10 Column('password', String(12))11 )12

13 classUser(object):14 def __init__(self, name, fullname, password):15 self.name =name16 self.fullname =fullname17 self.password =password18

19 mapper(User, user) #the table metadata is created separately with the Table construct, then associated with the User class via the mapper() function

最基本的表我们创建好了,那我们开始用orm创建一条数据试试:

1 #! /usr/bin/env python3

2 #-*- coding:utf-8 -*-

3 from sqlalchemy importcreate_engine4 from sqlalchemy.ext.declarative importdeclarative_base5 from sqlalchemy importColumn, Integer, String6 from sqlalchemy.orm importsessionmaker7

8 engine = create_engine("mysql+pymysql://root:Root-123@192.168.100.64/liuyouyuan?charset=utf8",echo=True)9

10 Base = declarative_base() #生成orm基类

11

12 classUser(Base):13 __tablename__ = 'user' #表名

14 id = Column(Integer, primary_key=True)15 name = Column(String(32))16 password = Column(String(64))17

18 Session_class = sessionmaker(bind=engine) #创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例

19 Session = Session_class() #生成session实例

20

21 user_obj = User(name="ZhaoLiyin", password="admin123") #生成你要创建的数据对象 也就是你要在user表中插入这样一条数据(这里只是一个对象)

22 print(user_obj.name, user_obj.id) #此时还没创建对象呢,不信你打印一下id发现还是None

23

24 Session.add(user_obj) #把要创建的数据对象添加到这个session里, 一会统一创建

25 print(user_obj.name, user_obj.id) #此时也依然还没创建

26 Session.commit() #现此才统一提交,创建数据

27 print(user_obj.name, user_obj.id) #此时也依然还没创建

运行结果:

1 ZhaoLiyin None2 ZhaoLiyin None3 2016-10-25 11:39:53,882 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'sql_mode'

4 2016-10-25 11:39:53,882INFO sqlalchemy.engine.base.Engine ()5 2016-10-25 11:39:53,885INFO sqlalchemy.engine.base.Engine SELECT DATABASE()6 2016-10-25 11:39:53,885INFO sqlalchemy.engine.base.Engine ()7 2016-10-25 11:39:53,886 INFO sqlalchemy.engine.base.Engine show collation where `Charset` = 'utf8' and `Collation` = 'utf8_bin'

8 2016-10-25 11:39:53,886INFO sqlalchemy.engine.base.Engine ()9 2016-10-25 11:39:53,887 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS CHAR(60)) AS anon_110 2016-10-25 11:39:53,887INFO sqlalchemy.engine.base.Engine ()11 2016-10-25 11:39:53,888 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS CHAR(60)) AS anon_112 2016-10-25 11:39:53,888INFO sqlalchemy.engine.base.Engine ()13 2016-10-25 11:39:53,889 INFO sqlalchemy.engine.base.Engine SELECT CAST('test collated returns'AS CHAR CHARACTER SET utf8) COLLATE utf8_bin AS anon_114 2016-10-25 11:39:53,889INFO sqlalchemy.engine.base.Engine ()15 2016-10-25 11:39:53,890INFO sqlalchemy.engine.base.Engine BEGIN (implicit)16 2016-10-25 11:39:53,892 INFO sqlalchemy.engine.base.Engine INSERT INTO user (name, password) VALUES (%s, %s)17 2016-10-25 11:39:53,892 INFO sqlalchemy.engine.base.Engine ('ZhaoLiyin', 'admin123')18 2016-10-25 11:39:53,893INFO sqlalchemy.engine.base.Engine COMMIT19 2016-10-25 11:39:53,896INFO sqlalchemy.engine.base.Engine BEGIN (implicit)20 2016-10-25 11:39:53,896INFO sqlalchemy.engine.base.Engine SELECT user.id AS user_id, user.name AS user_name, user.password AS user_password21 FROM user22 WHERE user.id = %s23 2016-10-25 11:39:53,896 INFO sqlalchemy.engine.base.Engine (2,)24 ZhaoLiyin 2

25

26 Process finished with exit code 0

注意代码中的三个print 对应的输出结果。明白什么时候数据才真正插入user表中。到这里真TM够了,是不是感觉很费劲才插入一条数据?别走,错过就没有下次了

查询:

1 #! /usr/bin/env python3

2 #-*- coding:utf-8 -*-

3 from orm_1 importUser4 from sqlalchemy importcreate_engine5 from sqlalchemy.orm importsessionmaker6

7 engine = create_engine("mysql+pymysql://root:Root-123@192.168.100.64/liuyouyuan?charset=utf8",echo=False)8 Session_class = sessionmaker(bind=engine) #创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例

9 Session = Session_class() #生成session实例

10 my_user = Session.query(User).filter_by(name="YangZi").first()11

12 print(my_user)13 print(my_user.id,my_user.name,my_user.password)

输出结果:

1

2 1 YangZi admin123

可以看出:sqlalchemy帮你把返回的数据映射成一个对象啦,这样你调用每个字段就可以跟调用对象属性一样。

不过刚才上面的显示的内存对象对址你是没办法分清返回的是什么数据的,除非打印具体字段看一下,如果想让它变的可读,只需在定义表的类下面加上这样的代码

1 def __repr__(self):2 return "" %(3 self.name, self.password)

修改:

1 my_user = Session.query(User).filter_by(name="alex").first()2

3 my_user.name = "Alex Li"

4

5 Session.commit()

回滚:

1 my_user = Session.query(User).filter_by(id=1).first()2 my_user.name = "Jack"

3

4

5 fake_user = User(name='Rain', password='12345')6 Session.add(fake_user)7

8 print(Session.query(User).filter(User.name.in_(['Jack','rain'])).all() ) #这时看session里有你刚添加和修改的数据

9

10 Session.rollback() #此时你rollback一下

11

12 print(Session.query(User).filter(User.name.in_(['Jack','rain'])).all() ) #再查就发现刚才添加的数据没有了。

13

14 #Session

15 #Session.commit()

获取所有数据:

1 print(Session.query(User.name,User.id).all())

多条件查询:

1 objs = Session.query(User).filter(User.id>0).filter(User.id<7).all()

上面2个filter的关系相当于 user.id >1 AND user.id <7 的效果

统计和分组:

1 Session.query(User).filter(User.name.like("Ra%")).count()

分组:

1 from sqlalchemy importfunc2 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

外键关联多对一

我们创建一个addresses表,跟user表关联

一个人有多个邮箱地址,或者说多个邮箱地址对应同一个人。这就要用到多对一。

1 #! /usr/bin/env python3

2 #-*- coding:utf-8 -*-

3

4 from sqlalchemy importForeignKey,create_engine5 from sqlalchemy.orm importrelationship6 from sqlalchemy importColumn, Integer, String7 from sqlalchemy.ext.declarative importdeclarative_base8 from sqlalchemy.orm importsessionmaker9

10

11 engine = create_engine("mysql+pymysql://root:admin123@localhost/test_db?charset=utf8")12 Base = declarative_base() #生成orm基类

13

14 Session_class = sessionmaker(bind=engine) #创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例

15 session = Session_class() #生成session实例

16

17

18 classUser(Base):19 __tablename__ = 'user' #表名

20 id = Column(Integer, primary_key=True,autoincrement=True)21 name = Column(String(32))22 password = Column(String(64))23

24 def __repr__(self):25 return "<%s name:%s password:%s>" %(self.id,self.name,self.password)26

27 classAddress(Base):28 """地址表,一个user有多个邮箱地址"""

29 __tablename__ = 'addresses'

30 id = Column(Integer, primary_key=True,autoincrement=True)31 email_address = Column(String(32), nullable=False)32 postal_code =Column(Integer)33 user_id = Column(Integer, ForeignKey('user.id')) #外键

34 user = relationship("User", backref="add")35 # 这句只用于查询。

36 # 功能1 相当于给Address这个表添加了一个属性列user,查询时可以用.user得到对应的User对象。但是这列不能插入数据,仅用于查询。

37 # 功能2 相当于给User这个表添加了一个属性列add,查询时在user表中可以通过.add得到Address对象。

38

39 def __repr__(self):40 return "email-%s postal_code-%s" %(self.email_address,self.postal_code)41

42 definit_db():43 Base.metadata.create_all(engine) #创建表结构

44

45 defdrop_db():46 Base.metadata.drop_all(engine) #删除

47

48

49 definser_test_data():50 init_db()51 name = ["杨幂", "赵丽颖", "刘亦菲","林志玲", "汤唯", "张馨予","赵伟彤", "陈意涵", "周冬雨","林心如", "范冰冰","梁静茹"]52 user_obj =[]53 #向user表中插入数据

54 for i in range(0,11):55 obj = User(name=name[i],password="admin")56 user_obj.append(obj)57 session.add_all(user_obj)58 session.commit()59

60 #addresses表中插入数据,这里要指定外键关联的user表中的主键

61 a1 = Address(email_address="yangmi@163.com",postal_code=12345,user_id=1)62 a2 = Address(email_address="YangMi@163.com",postal_code=12345,user_id=1)63 a3 = Address(email_address="zhaoliying@163.com",postal_code=12340,user_id=2)64 a4 = Address(email_address="ZhaoLiying@163.com",postal_code=12340,user_id=2)65 session.add_all([a1,a2,a3,a4])66 session.commit()67 print("Test data is inserted...")68

69 #inser_test_data()

70

71 add_obj = session.query(Address).filter_by(email_address="yangmi@163.com").first()72 print(add_obj.user) # 通过addresses表查询user

73 #<1 name:杨幂 password:admin>

74

75

76 user_obj = session.query(User).filter_by(id=2).first() #这样是取第一个对象

77 print(user_obj.add) # 通过user表查询对应的地址78 #[email-zhaoliying@163.com postal_code-12340, email-ZhaoLiying@163.com postal_code-12340]

79 print(user_obj.add[1].email_address)80 #ZhaoLiying@163.com

81

82 # session会话 query查询 filter过滤

83 # 这里filter的用法可以这样 filter(User.id>1) filter(User.id==1) filter_by(id=1)

多对多:

现实生活中

一个班级或者一门课程 可以对应多个学生

一个学生可以有多门课程或者报了多个班级

这就要用到多对多

grade表:

mysql> select * fromgrade;+----+--------+

| id | name |

+----+--------+

| 1 | Python |

| 2 | Linux |

| 3 | Go |

+----+--------+

3 rows in set (0.00 sec)

student表:

986023-20161102112801674-376675163.png

986023-20161102112819346-525021796.png

986023-20161102112832627-1811497807.png

986023-20161102112848065-1280535878.png

grade_student表:

mysql> select * fromgrade_student;+----------+------------+

| grade_id | student_id |

+----------+------------+

| 1 | 10 |

| 2 | 10 |

| 1 | 17 |

| 2 | 17 |

| 3 | 17 |

| 1 | 15 |

| 2 | 15 |

| 3 | 15 |

| 1 | 4 |

| 2 | 4 |

| 1 | 8 |

| 2 | 8 |

| 1 | 9 |

| 2 | 9 |

| 1 | 12 |

| 2 | 12 |

| 1 | 19 |

| 2 | 19 |

| 3 | 19 |

| 1 | 20 |

| 2 | 20 |

| 3 | 20 |

| 1 | 5 |

| 2 | 5 |

| 1 | 14 |

| 2 | 14 |

| 1 | 18 |

| 2 | 18 |

| 3 | 18 |

| 1 | 2 |

| 2 | 2 |

| 1 | 11 |

| 2 | 11 |

| 1 | 1 |

| 2 | 1 |

| 1 | 3 |

| 2 | 3 |

| 1 | 13 |

| 2 | 13 |

| 1 | 7 |

| 2 | 7 |

| 1 | 6 |

| 2 | 6 |

| 1 | 16 |

| 2 | 16 |

| 3 | 16 |

+----------+------------+

46 rows in set (0.00 sec)

完整代码示例:

1 #! /usr/bin/env python3

2 #-*- coding:utf-8 -*-

3

4 from sqlalchemy importForeignKey,create_engine5 from sqlalchemy.orm importrelationship6 from sqlalchemy importColumn, Integer, String7 from sqlalchemy.ext.declarative importdeclarative_base8 from sqlalchemy.orm importsessionmaker9

10

11 engine = create_engine("mysql+pymysql://root:admin123@localhost/test_db?charset=utf8")12 Base = declarative_base() #生成orm基类

13

14 Session_class = sessionmaker(bind=engine) #创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例

15 session = Session_class() #生成session实例

16

17

18 #! /usr/bin/env python3

19 #-*- coding:utf-8 -*-

20

21 from sqlalchemy importTable, Column, Integer,String, ForeignKey22 from sqlalchemy.orm importrelationship23 from sqlalchemy.ext.declarative importdeclarative_base24

25

26 from sqlalchemy importcreate_engine27 from sqlalchemy.orm importsessionmaker28

29

30 engine = create_engine("mysql+pymysql://root:admin123@localhost/test_db?charset=utf8")31 Base =declarative_base()32

33 SessionCls = sessionmaker(bind=engine) #创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例

34 session =SessionCls()35

36 grade_m2m_student = Table('grade_student', Base.metadata,37 Column('grade_id', Integer, ForeignKey('grade.id')),38 Column('student_id', Integer, ForeignKey('student.id')),39 )40

41 class Grade(Base): #定义班级表

42 """班级表"""

43 __tablename__ = 'grade' #表名

44 id = Column(Integer, primary_key=True,autoincrement=True)45 name = Column(String(32))46

47 def __repr__(self):48 return "id:%s name:%s>" %(self.id,self.name)49

50 classStudent(Base):51 """学生表"""

52 __tablename__ = 'student'

53 id = Column(Integer, primary_key=True,autoincrement=True)54 name = Column(String(32))55 qq = Column(String(32))56 grades = relationship("Grade",secondary=grade_m2m_student,backref="students")57

58 def __repr__(self):59 return "id:%s name:%s qq:%s>" %(self.id,self.name,self.qq)60

61 definit_db():62 Base.metadata.create_all(engine) #创建表结构

63

64 defdrop_db():65 Base.metadata.drop_all(engine) #删除

66

67 defcreate_grade(name):68 obj = Grade(name=name)69 returnobj70

71 defcreate_student(name,qq):72 obj = Student(name=name,qq=qq)73 returnobj74

75

76 #drop_db() # 删除表结构

77 #init_db() # 创建表结构

78 #79 ## 创建三个班级

80 #grade_obj = []

81 #grades = ["Python","Linux","Go"]

82 #for grade in grades:

83 #obj = create_grade(grade)

84 #grade_obj.append(obj)

85 #session.add_all(grade_obj)

86 #session.commit()

87 #88 ## 添加多个学生

89 #stu_obj = []

90 #students = [("杨幂","10001"),("赵丽颖","10002"),("刘亦菲","10003"),("胡歌","10004"),("勒布朗","10005"),("科比","10006"),("布兰妮","10007"),("林志玲","10008"),

91 #("汤唯", "10009"),("张馨予","10010"),("赵伟彤","10011"),("李四","10012"),("王宝强","10013"),

92 #("陈意涵", "10014"),("周冬雨","10015"),("林心如","10016"),("范冰冰","10017"),("梁静茹","10018"),("武藤兰","10019"),("小苍","10020"),]

93 #for i in range(0,14):

94 #obj = create_student(students[i][0],students[i][1])

95 #obj.grades = [grade_obj[0],grade_obj[1]] # 为学生关联班级

96 #stu_obj.append(obj)

97 #for j in range(14,20):

98 #obj = create_student(students[j][0], students[j][1])

99 # obj.grades = grade_obj # 为学生关联班级

100 #stu_obj.append(obj)

101 #session.add_all(stu_obj)

102 #session.commit()

103 #print("ok...")

104

105 # 从grade表中通过.students查询Python班 所有的学生

106 grade_obj = session.query(Grade).filter_by(name="Python").first()107 for stu ingrade_obj.students:108 print(stu)109 print("----------------------------------------------------------")110

111 # 从stu 表中 通过.grades查询 id为4的学生所在的 所有班级

112 student_obj = session.query(Student).filter_by(id=4).first()113 print(student_obj.grades)114

115

116 #运行结果:

117 #id:10 name:张馨予 qq:10010>

118 #id:17 name:范冰冰 qq:10017>

119 #id:15 name:周冬雨 qq:10015>

120 #id:4 name:胡歌 qq:10004>

121 #id:8 name:林志玲 qq:10008>

122 #id:9 name:汤唯 qq:10009>

123 #id:12 name:李四 qq:10012>

124 #id:19 name:武藤兰 qq:10019>

125 #id:20 name:小苍 qq:10020>

126 #id:5 name:勒布朗 qq:10005>

127 #id:14 name:陈意涵 qq:10014>

128 #id:18 name:梁静茹 qq:10018>

129 #id:2 name:赵丽颖 qq:10002>

130 #id:11 name:赵伟彤 qq:10011>

131 #id:1 name:杨幂 qq:10001>

132 #id:3 name:刘亦菲 qq:10003>

133 #id:13 name:王宝强 qq:10013>

134 #id:7 name:布兰妮 qq:10007>

135 #id:6 name:科比 qq:10006>

136 #id:16 name:林心如 qq:10016>

137 #----------------------------------------------------------

138 #[id:1 name:Python>, id:2 name:Linux>]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值