SQLAlchemy,python的orm框架

SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。

SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如:

MySQL-Python
    mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
   
pymysql
    mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
   
MySQL-Connector
    mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
   
cx_Oracle
    oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
   
更多详见:http://docs.sqlalchemy.org/en/latest/dialects/index.html

一、底层处理

使用 Engine/ConnectionPooling/Dialect 进行数据库操作,Engine使用ConnectionPooling连接数据库,然后再通过Dialect执行SQL语句。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from sqlalchemy import create_engine
  
  
engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=5)
  
# 执行SQL
# cur = engine.execute(
#     "INSERT INTO hosts (host, color_id) VALUES ('1.1.1.22', 3)"
# )
  
# 新插入行自增ID
# cur.lastrowid
  
# 执行SQL
# cur = engine.execute(
#     "INSERT INTO hosts (host, color_id) VALUES(%s, %s)",[('1.1.1.22', 3),('1.1.1.221', 3),]
# )
  
  
# 执行SQL
# cur = engine.execute(
#     "INSERT INTO hosts (host, color_id) VALUES (%(host)s, %(color_id)s)",
#     host='1.1.1.99', color_id=3
# )
  
# 执行SQL
# cur = engine.execute('select * from hosts')
# 获取第一行数据
# cur.fetchone()
# 获取第n行数据
# cur.fetchmany(3)
# 获取所有数据
# cur.fetchall()

二、ORM功能使用

ORM框架的作用就是把数据库表的一行记录与一个对象互相做自动转换。 正确使用ORM的前提是了解关系数据库的原理。 ORM就是把数据库表的行与相应的对象建立关联,互相转换。 由于关系数据库的多个表还可以用外键实现一对多、多对多等关联,相应地, ORM框架也可以提供两个对象之间的一对多、多对多等功能。

 1 创建表

#coding:utf8
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
print(sqlalchemy.__version__)


engine = create_engine('sqlite:///dbyuan111.db', echo=True)#1 连接数据库

Base = declarative_base()#2 生成一个SQLORM基类

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    password = Column(String)

    def __repr__(self):
       return "<User(name='%s', fullname='%s', password='%s')>" % (
                            self.name, self.fullname, self.password)

Base.metadata.create_all(engine)  #3 创建所有表结构

ed_user = User(name='xiaoyu', fullname='Xiaoyu Liu', password='123')
# print(ed_user)
#3 这两行触发sessionmaker类下的__call__方法,return得到 Session实例,赋给变量session,所以session可以调用Session类下的add,add_all等方法
MySession = sessionmaker(bind=engine)
session = MySession()

# session.add(ed_user)
# our_user = session.query(User).filter_by(name='ed').first()
# SELECT * FROM users WHERE name="ed" LIMIT 1;
# session.add_all([
#     User(name='alex', fullname='Alex Li', password='456'),
#     User(name='alex', fullname='Alex old', password='789'),
#     User(name='peiqi', fullname='Peiqi Wu', password='sxsxsx')])

# session.commit()

#print(">>>",session.query(User).filter_by(name='ed').first())

#print(session.query(User).all())


#order_by前不加all()
# for row in session.query(User).order_by(User.id):
#      print('<<',row)


# for row in session.query(User).filter(User.name.in_(['alex', 'wendy', 'jack'])):#这里的名字是完全匹配
#     print(row)

# for row in session.query(User).filter(~User.name.in_(['ed', 'wendy', 'jack'])):
#     print(row)

#print(session.query(User).filter(User.name == 'ed').count())

#from sqlalchemy import and_, or_

# for row in session.query(User).filter(and_(User.name == 'ed', User.fullname == 'Ed Jones')):
#     print(row)

# for row in session.query(User).filter(or_(User.name == 'ed', User.name == 'wendy')):
#     print(row)

单表
单表
# #coding:utf8
#
# import sqlalchemy
# from sqlalchemy import create_engine
# from sqlalchemy.ext.declarative import declarative_base
# from sqlalchemy import Column, Integer, String,ForeignKey
# from sqlalchemy.orm import sessionmaker,relationship
#
#
# engine = create_engine('sqlite:///dbyuan2.db', echo=True)
#
# Base = declarative_base()
# #多对多:创建第三张表
# class Author2Book(Base):
#     __tablename__='author2book'
#
#     nid=Column(Integer,primary_key=True)
#     author_id=Column(Integer,ForeignKey("author.id"))
#     book_id=Column(Integer,ForeignKey("book.id"))
#
#
# class Publisher(Base):
#     __tablename__ = 'publisher'
#     #id = Column(Integer, primary_key=True)里的数据类型一定写整型(Integer)
#     id = Column(Integer, primary_key=True)
#     name = Column(String(20))
#     city = Column(String(20))
#     country = Column(String(20))
#
#
#     def __str__(self):
#         return self.name
#
# class Author(Base):
#     __tablename__ = 'author'
#     id = Column(Integer, primary_key=True)
#     name = Column(String(20))
#
#     def __str__(self):
#         return self.name
#
# class AuthorDetail(Base):
#     __tablename__ = 'author_detail'
#
#     id = Column(Integer, primary_key=True)
#     sex = Column(String(20),default='male')
#     email =Column(String(20),default='123@qq.com')
#     address = Column(String(20),default='beijing')
#     birthday =Column(String(20))
#     author = Column(String(20),ForeignKey('author.id'),unique=True)#一对一
#
# class Book(Base):
#     __tablename__ = 'book'
#
#     id = Column(Integer, primary_key=True)
#     title = Column(String(20))
#     publisher_id = Column(String(20),ForeignKey('publisher.id'))#一对多
#     publication_date = Column(String(20))
#     price=Column(String(20))
#
#     def __str__(self):
#         return self.title
#
#
#
#
# Base.metadata.create_all(engine)
#
# Session = sessionmaker(bind=engine)
# session = Session()
#
#
# b1= Book(title='PHP',publisher_id=1,publication_date='2016-8-24',price=100)
# b2= Book(title='python',publisher_id=3,publication_date='2017-8-24',price=210)
# b3= Book(title='java',publisher_id=2,publication_date='2018-8-24',price=90)
#
# a1=Author(name='alex')
# a2=Author(name='alvin')
#
# ad1=AuthorDetail(birthday='1980-2-16',author=1)
# ad2=AuthorDetail(birthday='1990-3-16',author=1)
#
#
# p1=Publisher(name='北大出版社',city='北京',country='中国')
# p2=Publisher(name='河大出版社',city='保定',country='中国')
# p3=Publisher(name='中国机械出版社',city='北京',country='中国')
#
# ab1=Author2Book(author_id=1,book_id=1)
# ab2=Author2Book(author_id=1,book_id=2)
# ab3=Author2Book(author_id=2,book_id=2)
#
#
# session.add_all([a1,a2,ad1,ad2,b1,b2,b3,p1,p2,p3,ab1,ab2,ab3])
# session.commit()

####################################################
#很明显,这种建立表关系的方式不够直接和简单.




#coding:utf8

import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String,ForeignKey
from sqlalchemy.orm import sessionmaker,relationship


engine = create_engine('sqlite:///dbyuan242246.db', echo=True)

Base = declarative_base()
#多对多:创建第三张表
class Author2Book(Base):
    __tablename__='author2book'

    nid=Column(Integer,primary_key=True)
    author_id=Column(Integer,ForeignKey("author.id"))
    book_id=Column(Integer,ForeignKey("book.id"))


class Publisher(Base):
    __tablename__ = 'publisher'
    #id = Column(Integer, primary_key=True)里的数据类型一定写整型(Integer)
    id = Column(Integer, primary_key=True)
    name = Column(String(20))
    city = Column(String(20))
    country = Column(String(20))


    def __str__(self):
        return self.name

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

    book_obj_list=relationship('Book',secondary=Author2Book.__table__,backref='author_obj_list')#多对多的relationship如是写,有一个secondary


    def __str__(self):
        return self.name

class AuthorDetail(Base):
    __tablename__ = 'author_detail'

    id = Column(Integer, primary_key=True)
    sex = Column(String(20),default='male')
    email =Column(String(20),default='123@qq.com')
    address = Column(String(20),default='beijing')
    birthday =Column(String(20))
    author = Column(String(20),ForeignKey('author.id'),unique=True)#一对一

class Book(Base):
    __tablename__ = 'book'

    id = Column(Integer, primary_key=True)
    title = Column(String(20))
    publisher_id = Column(String(20),ForeignKey('publisher.id'))#一对多

    publisher_obj_list=relationship('Publisher',backref='book_obj_list')#一对多的relationship如是写


    publication_date = Column(String(20))
    price=Column(String(20))


    def __str__(self):
        return self.title




Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)
session = Session()

#publisher_id不用加上啦
b1= Book(title='PHP',publication_date='2016-8-24',price=100)
b2= Book(title='python',publication_date='2017-8-24',price=210)
b3= Book(title='java',publication_date='2018-8-24',price=90)

a1=Author(name='alex')
a2=Author(name='alvin')

ad1=AuthorDetail(birthday='1980-2-16',author=1)
ad2=AuthorDetail(birthday='1990-3-16',author=2)


p1=Publisher(name='北大出版社',city='北京',country='中国')
p2=Publisher(name='河大出版社',city='保定',country='中国')
p3=Publisher(name='中国机械出版社',city='北京',country='中国')

# ab1=Author2Book(author_id=1,book_id=1)
# ab2=Author2Book(author_id=1,book_id=2)
# ab3=Author2Book(author_id=2,book_id=2)
#第三张表就不用插入数据了

#建立多对多的关系,增加关系用append:b1.author_obj_list.append([a1,a2])
b1.author_obj_list=[a1,a2]
b2.author_obj_list=[a1,a2]

b1.publisher_obj_list=p1
# b1.publisher_obj_list=[p1,p2,p3]这样会报错,因为一对多的关系,b1.publisher_obj_list不可能绑定多个对象,反过来可以,如下
p1.book_obj_list=[b1,b2,b3]


'''
大家思考:b1.publisher_obj_list=p1与p1.book_obj_list=b1效果相同吗?
其实是一样的,举个例子:书法协会作为一个团体招人,alex也想进入该协会,两个动作都可以完成这件事:
书法协会作为主体把alex招了进来
alex作为主体加入了该组织
'''

'''
注意点:
ret = session.query(Users).all()
  有all().first()等,ret是对象列表;没有,则是sql语句
关联查询
  r = session.query(Book.title,Publisher.name).join(Publisher).all()
  r = session.query(Author2Book).join(Author).all()

'''
session.add_all([a1,a2,ad1,ad2,b1,b2,b3,p1,p2,p3])
session.commit()

关系表

2 操作表

obj = Users(name="alex0", extra='sb')
session.add(obj)
session.add_all([
    Users(name="alex1", extra='sb'),
    Users(name="alex2", extra='sb'),
])
session.commit()

增
session.query(Users).filter(Users.id > 2).delete()
session.commit()
session.query(Users).filter(Users.id > 2).update({"name" : "099"})
session.query(Users).filter(Users.id > 2).update({Users.name: Users.name + "099"}, synchronize_session=False)
session.query(Users).filter(Users.id > 2).update({"num": Users.num + 1}, synchronize_session="evaluate")
session.commit()
ret = session.query(Users).all()
ret = session.query(Users.name, Users.extra).all()
ret = session.query(Users).filter_by(name='alex').all()
ret = session.query(Users).filter_by(name='alex').first()
# 条件
ret = session.query(Users).filter_by(name='alex').all()
ret = session.query(Users).filter(Users.id > 1, Users.name == 'eric').all()
ret = session.query(Users).filter(Users.id.between(1, 3), Users.name == 'eric').all()
ret = session.query(Users).filter(Users.id.in_([1,3,4])).all()
ret = session.query(Users).filter(~Users.id.in_([1,3,4])).all()
ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='eric'))).all()
from sqlalchemy import and_, or_
ret = session.query(Users).filter(and_(Users.id > 3, Users.name == 'eric')).all()
ret = session.query(Users).filter(or_(Users.id < 2, Users.name == 'eric')).all()
ret = session.query(Users).filter(
    or_(
        Users.id < 2,
        and_(Users.name == 'eric', Users.id > 3),
        Users.extra != ""
    )).all()


# 通配符
ret = session.query(Users).filter(Users.name.like('e%')).all()
ret = session.query(Users).filter(~Users.name.like('e%')).all()

# 限制
ret = session.query(Users)[1:2]

# 排序
ret = session.query(Users).order_by(Users.name.desc()).all()
ret = session.query(Users).order_by(Users.name.desc(), Users.id.asc()).all()

# 分组
from sqlalchemy.sql import func

ret = session.query(Users).group_by(Users.extra).all()
ret = session.query(
    func.max(Users.id),
    func.sum(Users.id),
    func.min(Users.id)).group_by(Users.name).all()

ret = session.query(
    func.max(Users.id),
    func.sum(Users.id),
    func.min(Users.id)).group_by(Users.name).having(func.min(Users.id) >2).all()

# 连表

ret = session.query(Users, Favor).filter(Users.id == Favor.nid).all()

ret = session.query(Person).join(Favor).all()

ret = session.query(Person).join(Favor, isouter=True).all()


# 组合
q1 = session.query(Users.name).filter(Users.id > 2)
q2 = session.query(Favor.caption).filter(Favor.nid < 2)
ret = q1.union(q2).all()

q1 = session.query(Users.name).filter(Users.id > 2)
q2 = session.query(Favor.caption).filter(Favor.nid < 2)
ret = q1.union_all(q2).all()

其它
原文地址:https://www.cnblogs.com/935415150wang/p/7263826.html