对象-关系映射(Object/Relation Mapping,简称ORM),是随着面向对象的软件开发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据没法直接表达多对多关联和继承关系。所以,对象-关系映射(ORM)系统通常以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。node
面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别。为了解决这个不匹配的现象,对象关系映射技术应运而生。O/R中字母O起源于"对象"(Object),而R则来自于"关系"(Relational)。几乎全部的程序里面,都存在对象和关系数据库。在业务逻辑层和用户界面层中,咱们是面向对象的。当对象信息发生变化的时候,咱们须要把对象的信息保存在关系数据库中。python
当开发一个应用程序的时候(不使用O/R Mapping),可能会写很多数据访问层的代码,用来从数据库保存,删除,读取对象信息,等等。在DAL中写了不少的方法来读取对象数据,改变状态对象等等任务。而这些代码写起来老是重复的。mysql
若是开你最近的程序,看看DAL代码,确定会看到不少近似的通用的模式。咱们以保存对象的方法为例,传入一个对象,为SqlCommand对象添加SqlParameter,把全部属性和对象对应,设置SqlCommand的CommandText属性为存储过程,而后运行SqlCommand。对于每一个对象都要重复的写这些代码。 除此以外,还有更好的办法吗?有,引入一个O/R Mapping。实质上,一个O/R Mapping会为你生成DAL。与其本身写DAL代码,不如用O/R Mapping。用O/R Mapping保存,删除,读取对象,O/R Mapping负责生成SQL,你只须要关心对象就好。对象关系映射成功运用在不一样的面向对象持久层产品中,sql
•ORM:及Object-Relational Mapping,把关系数据库的表结构映射到对象上数据库
•咱们先来可能一个例子:数组
•若是咱们从数据库查出来几条数据,须要你在python中表示出来,若是你没有接触过ORM技术,你或许会使用下面的形式来存储这个数据:安全
[ (1, ‘feng’), (2, ‘shang’), (3, ‘huo’), ]
若是你想知道表结构是什么样的,是否是就费劲了,若是你想快速的取出其中的元素,就须要听听ORM的思想了。bash
数据库中每次查出来的数据都用一个类表示,这个类的属性和数据库中表的字段一一对应。多条数据,就是一个list,每一行数据都是一个类来表示,以下所示:session
class User(object): def __init__(self, id, name): self.id = id self.name = name [ User(1, “feng”), User(2, “shang”), User(3, “huo”), ]
当咱们须要得到id,或者name的时候,只须要经过循环获取到对象,直接经过user1.id或者user1.name就能够获取到id和name的属性。而且使得数据的存取很是的规范,这样ORM架构应用而生。架构
Python中最有名的ORM架构就是SQLAlchemy,咱们主要就是来学习SQLAlchemy的使用
pip install SQLAlchemy
yum install mysql-server mysql service mysqld restart sysctmctl restart mysql.service
create database sqlalchemy;
GRANT ALL PRIVILEGES ON *.* TO 'fxq'@'%' IDENTIFIED BY ‘123456’;
from sqlalchemy import create_engine engine = create_engine('mysql://fxq:123456@192.168.100.101/sqlalchemy', echo=True)
echo参数为True时,会显示每条执行的SQL语句,能够关闭,
create_engine()返回一个Engine的实例,而且它表示经过数据库语法处理细节的核心接口,在这种状况下,数据库语法将会被解释成python的类方法。
解释说明:
mysql://fxq:123456@192.168.100.101/sqlalchemy
mysql: 指定是哪一种数据库链接
第一个fxq: 用户名
123456: fxq用户对应的密码
192.168.100.101: 数据库的ip
sqlalchemy: 数据库须要链接库的名字
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker sql = '''create table student( id int not null primary key, name varchar(50), age int, address varchar(100)); ''' engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') conn = engine.connect() conn.execute(sql) engine.connect() #表示获取到数据库链接。相似咱们在MySQLdb中游标course的做用。
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/10 21:58 # @Author : Feng Xiaoqing # @File : demo2.py # @Function: ----------- from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') metadata = MetaData(engine) student = Table('student', metadata, Column('id', Integer, primary_key=True), Column('name', String(50), ), Column('age', Integer), Column('address', String(10)), ) metadata.create_all(engine)
以上方式均可以建立数据库表
MetaData类主要用于保存表结构,链接字符串等数据,是一个多表共享的对象
metadata = MetaData(engine) #绑定一个数据源的metadata
metadata.create_all(engine) #是来建立表,这个操做是安全的操做,会先判断表是否存在。
构造函数:
Table.__init__(self, name, metadata,*args, **kwargs)
name 表名
metadata 共享的元数据
*args Column 是列定义,详见下一节
下面是可变参数 **kwargs 定义
schema 此表的结构名称,默认None
autoload 自动从现有表中读入表结构,默认False
autoload_with 从其余engine读取结构,默认None
include_columns 若是autoload设置为True,则此项数组中的列明将被引用,没有写的列明将被忽略,None表示全部都列明都引用,默认None
mustexist 若是为True,表示这个表必须在其余的python应用中定义,必须是metadata的一部分,默认False
useexisting 若是为True,表示这个表必须被其余应用定义过,将忽略结构定义,默认False
owner 表全部者,用于Orcal,默认None
quote 设置为True,若是代表是SQL关键字,将强制转义,默认False
quote_schema 设置为True,若是列明是SQL关键字,将强制转义,默认False
mysql_engine mysql专用,能够设置'InnoDB'或'MyISAM'
构造函数:
Column.__init__(self, name, type_, *args, **kwargs)
一、name 列名
二、type_ 类型,更多类型 sqlalchemy.types
三、*args Constraint(约束), ForeignKey(外键), ColumnDefault(默认), Sequenceobjects(序列)定义
四、key 列名的别名,默认None
下面是可变参数 **kwargs
五、primary_key 若是为True,则是主键
六、nullable 是否可为Null,默认是True
七、default 默认值,默认是None
八、index 是不是索引,默认是True
九、unique 是否惟一键,默认是False
十、onupdate 指定一个更新时候的值,这个操做是定义在SQLAlchemy中,不是在数据库里的,当更新一条数据时设置,大部分用于updateTime这类字段
十一、autoincrement 设置为整型自动增加,只有没有默认值,而且是Integer类型,默认是True
十二、quote 若是列明是关键字,则强制转义,默认False
说到数据库,就离不开Session。Session的主要目的是创建与数据库的会话,它维护你加载和关联的全部数据库对象。它是数据库查询(Query)的一个入口。
在Sqlalchemy中,数据库的查询操做是经过Query对象来实现的。而Session提供了建立Query对象的接口。
Query对象返回的结果是一组同一映射(Identity Map)对象组成的集合。事实上,集合中的一个对象,对应于数据库表中的一行(即一条记录)。所谓同一映射,是指每一个对象有一个惟一的ID。若是两个对象(的引用)ID相同,则认为它们对应的是相同的对象。
要完成数据库查询,就须要创建与数据库的链接。这就须要用到Engine对象。一个Engine多是关联一个Session对象,也可能关联一个数据库表。
固然Session最重要的功能仍是实现原子操做。
ORM经过session与数据库创建链接进行通讯,以下所示:
from sqlalchemy.orm import sessionmaker DBSession = sessionmaker(bind=engine) session = DBSession()
经过sessionmake方法建立一个Session工厂,而后在调用工厂的方法来实例化一个Session对象。
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/10 20:58 # @Author : Feng Xiaoqing # @File : demo1.py # @Function: ----------- from sqlalchemy import create_engine, Column, Integer, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') DBsession = sessionmaker(bind=engine) session = DBsession() Base = declarative_base() class Student(Base): __tablename__ = 'student' id = Column(Integer, primary_key=True) name = Column(String(100)) age = Column(Integer) address = Column(String(100)) student1 = Student(id=1001, name='ling', age=25, address="beijing") student2 = Student(id=1002, name='molin', age=18, address="jiangxi") student3 = Student(id=1003, name='karl', age=16, address="suzhou") session.add_all([student1, student2, student3]) session.commit() session.close()
查询是这个里面最为复杂,最为繁琐的一个步骤。
经过Session的query()方法建立一个查询对象。这个函数的参数数量是可变的,参数能够是任何类或者是类的描述的集合。下面来看一个例子:
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/11 21:49 # @Author : Feng Xiaoqing # @File : search.py # @Function: ----------- from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Student(Base): __tablename__ = 'student' id = Column(Integer, primary_key=True) name = Column(String(50)) age = Column(Integer) address = Column(String(100)) engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') DBSession = sessionmaker(bind=engine) session = DBSession() my_stdent = session.query(Student).filter_by(name="fengxiaoqing2").first() print(my_stdent)
此时咱们看到的输出结果是这样的:
<__main__.Student object at 0x032745F0>
前面咱们在赋值的时候,咱们能够经过实例化一个对象,而后直接映射到数据库中,那咱们在查询出来的数据sqlalchemy直接给映射成一个对象了(或者是每一个元素为这种对象的列表),对象和咱们建立表时候的class是一致的,咱们就也能够直接经过对象的属性就能够直接调用就能够了。
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/11 21:49 # @Author : Feng Xiaoqing # @File : search.py # @Function: ----------- from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Student(Base): __tablename__ = 'student' id = Column(Integer, primary_key=True) name = Column(String(50)) age = Column(Integer) address = Column(String(100)) engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') DBSession = sessionmaker(bind=engine) session = DBSession() my_stdent = session.query(Student).filter_by(name="fengxiaoqing2").first() print(my_stdent.id,my_stdent.name,my_stdent.age,my_stdent.address)
结果:
1000311 fengxiaoqing2 182 chengde
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/11 21:49 # @Author : Feng Xiaoqing # @File : search.py # @Function: ----------- from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Student(Base): __tablename__ = 'student' id = Column(Integer, primary_key=True) name = Column(String(50)) age = Column(Integer) address = Column(String(100)) engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') DBSession = sessionmaker(bind=engine) session = DBSession() my_stdent = session.query(Student).filter(Student.name.like("%feng%")) print(my_stdent)
结果:
SELECT student.id AS student_id, student.name AS student_name, student.age AS student_age, student.address AS student_address FROM student WHERE student.name LIKE %s
根据结果,咱们能够看出来
filter_by最后的结果就是一个sql语句,咱们排错的时候就能够经过这个来排查咱们sql是否正确。
如下的这些过滤操做均可以在filter函数中使用:
equals: query(Student).filter(Student.id == 10001) not equals: query(Student).filter(Student.id != 100) LIKE: query(Student).filter(Student.name.like(“%feng%”)) IN: query(Student).filter(Student.name.in_(['feng', 'xiao', 'qing'])) not in query(Student).filter(~Student.name.in_(['feng', 'xiao', 'qing'])) AND: from sqlalchemy import and_ query(Student).filter(and_(Student.name == 'fengxiaoqing', Student.id ==10001)) 或者 query(Student).filter(Student.name == 'fengxiaoqing').filter(Student.address == 'chengde') OR: from sqlalchemy import or_ query.filter(or_(Student.name == 'fengxiaoqing', Student.age ==18))
all() 返回一个列表
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/11 21:49 # @Author : Feng Xiaoqing # @File : search.py # @Function: ----------- from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Student(Base): __tablename__ = 'student' id = Column(Integer, primary_key=True) name = Column(String(50)) age = Column(Integer) address = Column(String(100)) engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') DBSession = sessionmaker(bind=engine) session = DBSession() my_stdent = session.query(Student).filter(Student.name.like("%feng%")).all() print(my_stdent)
结果:
[<__main__.Student object at 0x031405B0>, <__main__.Student object at 0x030FCA70>, <__main__.Student object at 0x031405F0>]
能够经过遍历列表来获取每一个对象。
one() 返回且仅返回一个查询结果。当结果的数量不足一个或者多于一个时会报错。
把上面的all改为one就报错了。
first() 返回至多一个结果,并且以单项形式,而不是只有一个元素的tuple形式返回这个结果.
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/11 21:49 # @Author : Feng Xiaoqing # @File : search.py # @Function: ----------- from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Student(Base): __tablename__ = 'student' id = Column(Integer, primary_key=True) name = Column(String(50)) age = Column(Integer) address = Column(String(100)) engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') DBSession = sessionmaker(bind=engine) session = DBSession() my_stdent = session.query(Student).filter(Student.name.like("%feng%")).first() print(my_stdent)
结果:
<__main__.Student object at 0x030A3610>
Filter: 能够像写 sql 的 where 条件那样写 > < 等条件,但引用列名时,须要经过 类名.属性名 的方式。
filter_by: 可使用 python 的正常参数传递方法传递条件,指定列名时,不须要额外指定类名。,参数名对应名类中的属性名,但彷佛不能使用 > < 等条件。
当使用filter的时候条件之间是使用“==",fitler_by使用的是"="。
user1 = session.query(User).filter_by(id=1).first() user1 = session.query(User).filter(User.id==1).first()
filter不支持组合查询,只能连续调用filter来变相实现。
而filter_by的参数是**kwargs,直接支持组合查询。
好比:
q = sess.query(IS).filter(IS.node == node and IS.password == password).all()
更新就是查出来,直接更改就能够了
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/11 22:27 # @Author : Feng Xiaoqing # @File : update.py # @Function: ----------- from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Student(Base): __tablename__ = 'student' id = Column(Integer, primary_key=True) name = Column(String(50)) age = Column(Integer) address = Column(String(100)) engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') DBSession = sessionmaker(bind=engine) session = DBSession() my_stdent = session.query(Student).filter(Student.id == 1002).first() my_stdent.name = "fengxiaoqing" my_stdent.address = "chengde" session.commit() student1 = session.query(Student).filter(Student.id == 1002).first() print(student1.name, student1.address)
结果:
MariaDB [sqlalchemy]> select * from student; +---------+---------------+------+---------+ | id | name | age | address | +---------+---------------+------+---------+ | 1002 | molin | 18 | jiangxi | | 1003 | karl | 16 | suzhou | | 100011 | fengxiaoqing | 18 | chengde | | 100021 | fengxiaqing1 | 181 | chengde | | 1000111 | fengxiaoqing | 18 | chengde | | 1000211 | fengxiaqing1 | 181 | chengde | | 1000311 | fengxiaoqing2 | 182 | chengde | +---------+---------------+------+---------+ 7 rows in set (0.00 sec) MariaDB [sqlalchemy]> select * from student; +---------+---------------+------+---------+ | id | name | age | address | +---------+---------------+------+---------+ | 1002 | fengxiaoqing | 18 | chengde | | 1003 | karl | 16 | suzhou | | 100011 | fengxiaoqing | 18 | chengde | | 100021 | fengxiaqing1 | 181 | chengde | | 1000111 | fengxiaoqing | 18 | chengde | | 1000211 | fengxiaqing1 | 181 | chengde | | 1000311 | fengxiaoqing2 | 182 | chengde | +---------+---------------+------+---------+ 7 rows in set (0.00 sec) MariaDB [sqlalchemy]>
删除其实也是跟查询相关的,直接查出来,调用delete()方法直接就能够删除掉。
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/11 22:27 # @Author : Feng Xiaoqing # @File : update.py # @Function: ----------- from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Student(Base): __tablename__ = 'student' id = Column(Integer, primary_key=True) name = Column(String(50)) age = Column(Integer) address = Column(String(100)) engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') DBSession = sessionmaker(bind=engine) session = DBSession() session.query(Student).filter(Student.id == 1001).delete() session.commit() session.close()
统计count()
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/11 22:27 # @Author : Feng Xiaoqing # @File : update.py # @Function: ----------- from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Student(Base): __tablename__ = 'student' id = Column(Integer, primary_key=True) name = Column(String(50)) age = Column(Integer) address = Column(String(100)) engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') DBSession = sessionmaker(bind=engine) session = DBSession() print(session.query(Student).filter(Student.name.like("%feng%")).count())
分组 group_by()
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/11 22:27 # @Author : Feng Xiaoqing # @File : update.py # @Function: ----------- from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Student(Base): __tablename__ = 'student' id = Column(Integer, primary_key=True) name = Column(String(50)) age = Column(Integer) address = Column(String(100)) engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') DBSession = sessionmaker(bind=engine) session = DBSession() std_group_by = session.query(Student).group_by(Student.age) print(std_group_by)
结果的sql语句以下:
SELECT student.id AS student_id, student.name AS student_name, student.age AS student_age, student.address AS student_address FROM student GROUP BY student.age
排序 order_by() 反序在order_by里面用desc()方法
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/11 22:27 # @Author : Feng Xiaoqing # @File : update.py # @Function: ----------- from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() class Student(Base): __tablename__ = 'student' id = Column(Integer, primary_key=True) name = Column(String(50)) age = Column(Integer) address = Column(String(100)) engine = create_engine('mysql+pymysql://fxq:123456@192.168.100.101/sqlalchemy') DBSession = sessionmaker(bind=engine) session = DBSession() std_ord_desc = session.query(Student).filter(Student.name.like("%feng%")).order_by(Student.id.desc()).all() for i in std_ord_desc: print(i.id)
结果:
1000311 1000211 1000111 100021 100011 1002