1.ORM介绍:

orm英文全称object relational mapping,就是对象映射关系程序,简单来说我们类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却都是关系型的,为了保证一致的使用习惯,通过orm将编程语言的对象模型和数据库的关系模型建立映射关系,这样我们在使用编程语言对数据库进行操作的时候可以直接使用编程语言的对象模型进行操作就可以了,而不用直接使用sql语言。等同于在数据库之上利用数据库提供的api再进行一次封装,将不同的sql结构、语句,转换成对象、属性等易于程序猿编写的code格式。

2.SQLAlchemy

SQLAlchemy是Python下的一款数据库对象关系映射(ORM)工具,能满足大多数数据库操作需求,同时支持多种数据库引擎(SQLite,MySQL,Postgresql,Oracle等)。所谓ORM(Object Relational Mapper)可以理解为“将数据库中的表映射为程序中的类”,表中的一行即为类的一个实例。比如Users表映射为User类,表中的一行数据映射为User()实例。
SQLAlchemy在Web开发中应用较多,但作为一个数据分析、数据挖掘人员,最好也能掌握这门灵活的数据库操作技术。
它的主要优点有:
对数据表的抽象,允许开发人员首先考虑数据模型,同时使得Python程序更加简洁易读。
对各种数据库引擎的封装,使得开发人员在面对不同数据库时,只需要做简单修改即可,工作量大大减少。

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

3.基础使用:

首先需要安装sqlalchemy包,直接pip安装:pip install sqlalchemy
代码中的注释很详细,就不再写了。

#Author :ywq
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column,Integer,String
from sqlalchemy.orm import sessionmaker
engine=create_engine('mysql+pymysql://ywq:qwe@192.168.0.71/test',
                     encoding='utf-8',echo=True)  #use mysql DB,and pymysql as the driver

Base=declarative_base()  #生成orm映射关系基类
'''
定义表结构和创建表
'''
class User(Base):
    __tablename__='user'
    id =Column(Integer,primary_key=True)
    name=Column(String(8))
    password=Column(String(16))

    # def __repr__(self):
    #     return "User(id=%i,name='%s',password='%s')" %(self.id,self.name,self.password)

Base.metadata.create_all(engine)  #连接engine,创建表结构,与一般子类调用父类不同,这里是
                                  # Base作为父类,调用所有上方创建的子类。

#Base.metadata.drop_all(engine)  # 删除所有表

Session_class=sessionmaker(bind=engine) #创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
Session=Session_class()  #创建session实例,可以把session理解成pymysql的游标
'''
insert data into table
'''
# user_table_obj=User(name='ywq',password='qwe') #生成想要创建的数据库表中的数据
# print(user_table_obj.name,user_table_obj.id)  #此时数据还未添加进库中,打印出来的结果为None
#
# Session.add(user_table_obj)
# print(user_table_obj.name,user_table_obj.id) #添加后发现还是为None,因为还没有commit提交
#
# Session.commit()
'''
del data from table
'''
#Session.delete(User(User.id !=1)) #just delete
#Session.query(User).filter(User.id != 1).delete()  #query then delete
'''
query data from table
'''
# field_user=Session.query(User).filter_by(name='ywq').first()
# print(field_user,field_user.name,field_user.id)  #field_user是一段内存映射对象,查看具体字段还要调用对象属性
#                                                 #为了查看方便,使返回的结果无需调用属性,直接查看,可以在class User
#                                                 #类中定义内置方法,如上注释部分
# print(Session.query(User.name,User.id,User.password).all()) #查看所有指定字段
objs = Session.query(User).filter(User.id>10).filter(User.id<15).all() #条件查询,查询出来的结果是一个list
for i in objs:print(i.name,i.id)

'''
modify data from table
'''
# user_table_obj=Session.query(User).filter_by(id=1).first()
# user_table_obj.name='ywq1'            #调用对象属性重新赋值即可立即修改表中字段
#
# Session.commit()
#
# '''
# rollback
# '''
# user_table_obj=Session.query(User).filter_by(name='ywq').first()
# user_table_obj.name='ywq2'
#
# user_table_add=User(name='cqy',password='qwe')
# Session.add(user_table_add)
#
# print(Session.query(User).filter(User.name.in_(['ywq','cqy'])).all())  #查看session里刚添加和修改的数据,此时数据还未commit
#
# Session.rollback()
# print(Session.query(User).filter(User.name.in_(['ywq','cqy'])).all()) #再次查看发现刚添加修改的数据没了
#


'''
advanced query
'''
users = Session.query(sqlalchemy.distinct(User.name))               # 去重查询,根据name进行去重
users = Session.query(User).order_by(User.name)                     # 排序查询,正序查询
users = Session.query(User).order_by(User.name.desc())              # 排序查询,倒序查询
users = Session.query(User).order_by(sqlalchemy.desc(User.name))    # 排序查询,倒序查询的另外一种形式

users = Session.query(User.id, User.name)                           # 只查询部分属性
users = Session.query(User.name.label("user_name"))                 # 结果集的列取别名

4.联表和外键

抛出问题:怎样实现一个使用对象的属性实现跨表的增删改查呢?

#Author :ywq
from sqlalchemy import Table, Column, Integer,String,DATE, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine=create_engine('mysql+pymysql://ywq:qwe@192.168.0.71/test?charset=utf8',
                     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')),
                        )


class Book(Base):
    __tablename__ = 'books'
    id = Column(Integer,primary_key=True)
    name = Column(String(64))
    authors = relationship('Author',secondary=book_m2m_author,backref='books')
    '''
    直接通过给类定义authors属性的方式,关联Author表中的实例,但book表和author表没有直接联系,得通过第三张纯外键表来实现,因此
    secondary=book_m2m_author的作用体现于此,backref='books',代表在book类中创建了author的属性的同时,在内容中会创建维护
    一个赋予给author类的属性,即可通过author.books来关联book中的实例。
    authors = relationship('Author',secondary=book_m2m_author,backref='books')
    可以这样理解它,假设已有book1,查询它的author,那么过程就是:
    author_id=session.query(book_m2m_author.author_id).filter(book_m2m_author.book_id==book1.id)
    author=session.query(authors).filter(authors.id==author_id)
    '''
    def __repr__(self):
        return self.name

class Author(Base):
    __tablename__ = 'authors'
    id = Column(Integer, primary_key=True)
    name = Column(String(32))

    def __repr__(self):
        return self.name

Base.metadata.create_all(engine)

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


b1 = Book(name="Byte of Python")
b2 = Book(name="Python核心编程")
b3 = Book(name="The zen of python")

a1 = Author(name="Alice")
a2 = Author(name="Bob")
a3 = Author(name="jack")

b1.authors = [a1,a2]   
b2.authors = [a1,a2,a3]  #直接给book实例的authors属性赋值,过程:1.先查询出book实例的表id 2.查出author实例的表id 
                            #3.在book_m2m_author表中记录books.id authors.id的对应关系 

s.add_all([b1,b2,b3,a1,a2,a3])

s.commit()

代码中注释已经很详细,不再细说。