SQLAlchemy的基本用法

ORM

ORM,对象关系映射,对象和关系之间的映射,使用面向对象的方式来操作数据库。

关系模型和Python对象之间的映射:    
table  => class ,  表映射为类  
row => object,     行映射为实例  
column => property,字段映射为属性  

举例
有表student,字段为id int,name varchar,age int 映射到Python如下:

class Student:
    id = ?   某类型字段    
    name = ? 某类型字段    
    age = ?  某类型字段

最终得到实例
class Student:    
    def __init__(self):
        self.id = ?
        self.name = ?
        self.age = ?


SQLAlchemy

SQLAlchemy 是一个ORM框架

  • 安装:$ pip install sqlalchemy

开发:QLAlchemy内部使用了连接池.

创建连接

数据库连接

import sqlalchemy

IP ='172.198.11.11'
USERNAME = 'yu'
PASSWORD = '123'
DATABASE = 'test'
PORT = 3306

engine = sqlalchemy.create_engine("mysql+pymysql://{}:{}@{}:{}/{}".\
        format(USERNAME,PASSWORD,IP,PORT,DATABASE), echo=True)
        
lazy connecting:懒连接。创建引擎并不会马上连接数据库,直到让数据库执行任务时才连接。
创建基类
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base() # ORM Mapping 创建基类,便于实体类继承
创建实例类
class Empl(Base):

    __tablename__ = "empl"  #映射,对应数据库中的表empl

    id = Column(Integer,primary_key=True,autoincrement=True) #定义字段的类型和属性
    name = Column(String(64),nullable=False)
    age = Column(Integer)

    def __repr__(self):
        return "<{} id={},name={},age={}>".format(
            __class__.__name__,self.id,self.name,self.age
        )
  • __tablename__指定表名(要注意大小写)
  • Column类指定对应的字段,必须指定
创建表
# Base.metadata.drop_all(engine)
# Base.metadata.create_all(engine)

加载表
from sqlalchemy import MetaData,Table

md = MetaData(bind=engine)
class Employees(Base):
    __table__ = Table("employees",md,autoload=True)  # 自动加载表

    def __repr__(self):   #__repr__ 函数可以通过打印emp来查看SQL语句来设置,与数据库中的表字段的顺序对应,方便打印查看
        return("{},emp_no={},birth_date={},first_name={},last_name={},gender={},hire_date={}".format(self.__class__.__name__,\
                self.emp_no,self.birth_date,self.first_name,self.last_name,self.gender,self.hire_date))
                
emp = session.query(Employees)
print(emp)
---------------------------------
SELECT employees.emp_no AS employees_emp_no, employees.birth_date AS employees_birth_date, employees.first_name AS employees_first_name, employees.last_name AS employees_last_name, employees.gender AS employees_gender, employees.hire_date AS employees_hire_date 
FROM employees
实例化
empl = Empl(id=1,name = 'jake')  #实例化
empl.name = 'tom'   #实例改属性,而name是类属性,(用到描述器)
empl.age = 20

创建会话session
  • 在一个会话中操作数据库,会话建立在连接上,连接被引擎管理。当第一次使用数据库时,从引擎维护的连接池中获取一个连接使用。
  • session对象线程不安全。所以不同线程应该使用不用的session对象。Session类和engine有一个就行了
Session = sessionmaker(bind=engine)   #创建会话
session = Session() #线程不安全
GURD 操作,增删改查
  • add():增加一个对象
  • add_all():可迭代对象,元素是对象
Session = sessionmaker(bind=engine)   #创建会话
session = Session() #线程不安全

empl = Empl()  #创建实例
empl.name = 'jurry'
empl.age = 23

session.add(empl)   # 增加一个对象
session.commit()

try:
    empl.name = 'jake'
    session.add_all([empl])  # add_all():可迭代对象,元素是对象
    session.commit()
except Exception as er:
    print(er)
    session.rollback()

主键没有值,就是新增;主键有值,就是找到主键对应的记录修改

简单查询

使用:query()方法,返回一个Query对象
em = session.query(Empl).filter(Employee.id > 10)

print(len(list(empl)))      #查到的为表Empl的总行数
em = session.query(Empl)  #query查询,empl 为返回的结果集
print(em)
em = session.query(Empl).get(1)    # 通过主键查询
print(em)
-------------------------------------
16
SELECT empl.id AS empl_id, empl.name AS empl_name, empl.age AS empl_age
FROM empl
Empl,id=1,name=jurry,age=10

query方法将实体类传入,返回类的对象可迭代对象,这时候并不查询。迭代它就执行SQL来查询数据库,封装数据到指定类的实例。get方法使用主键查询,返回一条传入类的一个实例。

先查询,后更改,再提交 (实质是更改实例属性)

em = session.query(Empl).get(2)  #查主键为2的实例
em.name = 'xw'
em.age = 18
session.add(em)
session.commit()
状态

每一个实体,都有一个状态属性_sa_instance_state,其类型是sqlalchemy.orm.state.InstanceState,可以使用sqlalchemy.inspect(entity)函数查看状态,常见的状态值有:transient,pending,persistent,deleted,detached.

状态说明
transient(暂时的)实体类尚未加入到session中,同时并没有保存到数据库中
pending(挂起的)transient的实体被add()到session中,状态切换到pending,但是它还没有flush到数据库中
persistent(持久的)session中的实体对象对应着数据库中的真实记录,pending状态在提交成功后可以变成persistent状态,或者查询成功返回实体也是persistent状态
deleted(删除的)实体被删除且已经flush但未commit完成,事务提交成功了实体变成detached,事务失败则返回persistent状态
detached(分离的)删除成功的实体进入这个状态
  • 新建一个实体,状态是transient临时的。一旦add()后从transient变成pending状态。成功commit()后从pending变成persistent状态。成功查询返回的实体对象,也是persistent状态。persistent状态的实体,修改依然是persistent状态。persistent状态的实体,删除后,flush后但没有commit,就变成deteled状态,成功提交,变为detached状态,提交失败,还原到persistent状态
  • flush方法,主动把改变应用到数据库中去。
  • 删除、修改操作,需要对应一个真实的记录,所以要求实体对象是persistent状态
删除
try:
    em = session.query(Empl).get(2)   #先查询
    session.delete(em)   # 后删除
    session.flush()      # 再flush
    session.commit()     # 再commit
except Exception as e:
    session.rollback()
    
sqlalchemy.orm.make_transient(emp)  #此方法删除后又可以找回来
session.add(emp)
session.commit()
    

复杂查询(AND条件,OR条件,NOT条件,IN条件,Like条件),用到了过滤器

与或非的运算符&、|、~,一定要在表达式上加上括号(加上括号安全)

# AND条件
from sqlalchemy import or_,and_,not_
# ems = session.query(Empl).filter(Empl.id>10 and Empl.age==25)  此方法不行
ems = session.query(Empl).filter(Empl.id>10).filter(Empl.age==25)  #下面四种方法都可以
ems = session.query(Empl).filter((Empl.id<10)&(Empl.age==25))
ems = session.query(Empl).filter(Empl.id<10,Empl.age==25)
ems = session.query(Empl).filter(and_(Empl.id<10,Empl.age==25))

# or条件
ems = session.query(Empl).filter(or_(Empl.id>12,Empl.id<3))
show(ems)
ems = session.query(Empl).filter((Empl.id>12)|(Empl.id<3))
show(ems)

# NOT条件
ems = session.query(Empl).filter(not_(Empl.id<10))   # not_ 是not加下划线
ems = session.query(Empl).filter(~(Empl.id<10))
show(ems)

# in 条件
id = [2,3,5]
ems = session.query(Empl).filter(Empl.id.in_(id))    # in_是in加下划线
ems = session.query(Empl).filter(Empl.id.notin_(id)) # notin_ 是notin加下划线

# like 条件
ems = session.query(Empl).filter(Empl.name.like('d%'))
ems = session.query(Empl).filter(Empl.name.notlike('d%')) 

排序
ems = session.query(Empl).filter(Empl.id>5).order_by(Empl.id) # 默认是升序 asc()
ems = session.query(Empl).filter(Empl.id>5).order_by(Empl.id.desc()) # 降序 desc()


# 多列排序
emp = session.query(Employees).filter(Employees.emp_no > 10010).order_by(Employees.last_name).order_by(Employees.emp_no.desc())
show(emp)

分页 (limit)
emp = session.query(Employees).limit(3)
show(emp)
emp = session.query(Employees).limit(3).offset(6)
show(emp)
-------------------------------------------
Employees,hire_date=1986-06-26,gender=M,first_name=Georgi,emp_no=10001,last_name=Facello,birth_date=1953-09-02
Employees,hire_date=1985-11-21,gender=F,first_name=Bezalel,emp_no=10002,last_name=Simmel,birth_date=1964-06-02
Employees,hire_date=1986-08-28,gender=M,first_name=Parto,emp_no=10003,last_name=Bamford,birth_date=1959-12-03
~~~~~~~~~~~~~~~~~~~~
Employees,hire_date=1989-02-10,gender=F,first_name=Tzvetan,emp_no=10007,last_name=Zielinski,birth_date=1957-05-23
Employees,hire_date=1994-09-15,gender=M,first_name=Saniya,emp_no=10008,last_name=Kalloufi,birth_date=1958-02-19
Employees,hire_date=1985-02-18,gender=F,first_name=Sumant,emp_no=10009,last_name=Peac,birth_date=1952-04-19
消费者方法

消费者方法调用后,Query对象(可迭代)就转换成了一个容器

emp = session.query(Employees)
print(len(list(emp)))
print(emp.count())

print(emp.all())
print(list(emp))
print(emp.first())

emp = session.query(Employees).get(10001)
session.delete(emp)
session.commit()

first方法本质上就是limit语句

聚合,分组(分组其实就是按字段查询)
from sqlalchemy import func
query = session.query(func.count(Employees.emp_no))
print(query.all)   
print(query.first())
print(query.one)
print(query.scalar())  # 取one()的第一个元素

print(session.query(func.max(Employees.emp_no)).scalar())
print(session.query(func.min(Employees.emp_no)).scalar())
print(session.query(func.avg(Employees.emp_no)).scalar())

query = session.query(Employees.gender,func.count(Employees.emp_no)).group_by(Employees.gender.desc()).all()   分组(分组其实就是按字段查询)

for i,j in query:
    print(i,j)
----------------------------------------------
[(19,)]
(19,)
<bound method Query.one of <sqlalchemy.orm.query.Query object at 0x000001B8CB6FCCC0>>
19
10020
10001
10010.9474
F 7
M 12

需求
查询10010员工的所在部门的编号和员工信息
1,使用隐式内连接(没有join)

result = session.query(Employees,Dept_emp).filter(Employees.emp_no==Dept_emp.emp_no).filter(Employees.emp_no==10010).all()
for i in result:
    print(i)
-----------------------------------------------------------
(emp_no=10010,birth_date=1963-06-01,first_name=Duangkaew,last_name=Piveteau,gender=F,hire_date=1989-08-24, dept_no=d004)
(emp_no=10010,birth_date=1963-06-01,first_name=Duangkaew,last_name=Piveteau,gender=F,hire_date=1989-08-24, dept_no=d006)

2,使用join连接

results = session.query(Employee).join(Dept_emp).filter(Employee.emp_no == 10010).all()
-----------------------------------------------------------
[emp_no=10010,birth_date=1963-06-01,first_name=Duangkaew,last_name=Piveteau,gender=F,hire_date=1989-08-24]
#返回都只有一行数据
  • 返回都只有一行数据,为什么?
  • 它们生成的SQL语句是一样的,执行该SQL语句返回确实是2行记录,可以Python中的返回值列表中只有一个元素?原因在于query(Employee)这个只能返回一个实体对象中去,为了解决这个问题,需要修改实体类Employee,增加属性用来存放部门信息
    sqlalchemy.orm.relationship(实体类名字符串)
from sqlalchemy.orm import relationship     # 导入模块
md = MetaData(bind=engine)
class Employees(Base):
    __table__ = Table("employees",md,autoload=True)
    department =relationship('Dept_emp')       # 增加关系属性         

result = session.query(Employees).join(Dept_emp).filter(Employees.emp_no == 10010).all()   # 运行过程中会生成等值条件,效率减低
print(result)
result= session.query(Employees).join(Dept_emp).filter(Employees.emp_no == Dept_emp.emp_no).filter(Employees.emp_no == 10010).all()
print(result)
results = session.query(Employees).join(Dept_emp, Employees.emp_no == Dept_emp.emp_no).filter(Employees.emp_no == 10010).all()
print(result)
----------------------------------------------------------------------------------------------------------------------
[emp_no=10010,birth_date=1963-06-01,first_name=Duangkaew,last_name=Piveteau,gender=F,hire_date=1989-08-24,department=[dept_no=d004, dept_no=d006]]
[emp_no=10010,birth_date=1963-06-01,first_name=Duangkaew,last_name=Piveteau,gender=F,hire_date=1989-08-24,department=[dept_no=d004, dept_no=d006]]
[emp_no=10010,birth_date=1963-06-01,first_name=Duangkaew,last_name=Piveteau,gender=F,hire_date=1989-08-24,department=[dept_no=d004, dept_no=d006]]

  • 第一种方法join(Dept_emp)中没有等值条件,会自动生成一个等值条件,如果后面有filter,哪怕是filter(Employee.emp_no == Dept_emp.emp_no),这个条件会在where中出现。第一种这种自动增加join的等值条件的方式不推荐.
  • 第二种方法在join中增加等值条件,阻止了自动的等值条件的生成。这种方式推荐
  • 第三种方法就是第二种
总结

  • 在开发中,一般都会采用ORM框架,这样就可以使用对象操作了.
  • 定义表映射的类,使用Column的描述器定义类属性,使用ForeignKey来定义外键约束
  • 如果在一个对象中,想查看其他表对应的对象的内容,就有使用relationship来定义关系
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy是一个Python编程语言下的SQL工具包和对象-关系映射器(ORM)。它提供了一种与数据库进行交互的高级抽象,使得开发人员可以使用Python语言来执行数据库操作,而不需要直接编写SQL语句。 下面是SQLAlchemy的使用详解: 1. 安装SQLAlchemy:可以使用pip命令来安装SQLAlchemy,如下所示: ``` pip install sqlalchemy ``` 2. 导入SQLAlchemy模块:在Python脚本中,首先需要导入SQLAlchemy模块,如下所示: ```python from sqlalchemy import create_engine, Column, Integer, String, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship ``` 3. 创建连接引擎:使用`create_engine()`函数创建一个数据库连接引擎,该引擎将负责与数据库进行通信。引擎的参数通常包括数据库的URL、用户名、密码等信息,如下所示: ```python engine = create_engine('数据库URL') ``` 4. 创建映射类:使用`declarative_base()`函数创建一个基类,该基类将作为所有映射类的父类。然后,使用`Column()`函数定义表的列,如下所示: ```python Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String) email = Column(String) ``` 5. 创建表:使用`Base.metadata.create_all()`方法创建数据库中的表,如下所示: ```python Base.metadata.create_all(engine) ``` 6. 创建会话:使用`sessionmaker()`函数创建一个会话工厂,然后使用工厂创建会话对象,如下所示: ```python Session = sessionmaker(bind=engine) session = Session() ``` 7. 执行数据库操作:通过会话对象,可以执行各种数据库操作,例如插入、查询、更新和删除数据,如下所示: ```python # 插入数据 user = User(name='John', email='john@example.com') session.add(user) session.commit() # 查询数据 users = session.query(User).all() for user in users: print(user.name, user.email) # 更新数据 user = session.query(User).filter_by(name='John').first() user.email = 'new_email@example.com' session.commit() # 删除数据 user = session.query(User).filter_by(name='John').first() session.delete(user) session.commit() ``` 这是SQLAlchemy基本使用方法。通过这些步骤,你可以使用Python来执行各种数据库操作,并且无需直接编写SQL语句。你还可以进一步学习SQLAlchemy的高级特性,如事务处理、关联关系等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值