• 0基础和我学python----SQLAlchemy框架(1)


    📢📢📢📣📣📣
    哈喽!大家好,我是「奇点」,江湖人称 singularity。刚工作几年,想和大家一同进步🤝🤝
    一位上进心十足的【Java ToB端大厂领域博主】!😜😜😜
    喜欢java和python,平时比较懒,能用程序解决的坚决不手动解决😜😜😜

    ✨ 如果有对【java】感兴趣的【小可爱】,欢迎关注我

    ❤️❤️❤️感谢各位大可爱小可爱!❤️❤️❤️
    ————————————————

    如果觉得本文对你有帮助,欢迎点赞,欢迎关注我,如果有补充欢迎评论交流,我将努力创作更多更好的文章。

    上篇我们讲到了python中常见的ORM框架,我们大致知道了python中有什么主流的ORM框架,并对不同的ORM框架的优缺点进行了比较,今天我们就来聊聊在Python中,最有名的ORM框架---SQLAlchemy。我们来看看SQLAlchemy的用法。

    📖 准备工作

    首先通过pip安装SQLAlchemy

    pip install sqlalchemy

    然后创建一个user表,用SQLAlchemy来试试:

    sql创语句如下

    create table user (id varchar(20) primary key, name varchar(20))

    第一步,导入SQLAlchemy,并初始化DBSession:

    💾 简介

    SQLAlchemy 是 Python SQL 工具包和对象关系映射器,它为应用程序开发人员提供了 SQL 的全部功能和灵活性。 它提供了一整套众所周知的企业级持久性模式,专为高效和高性能的数据库访问而设计,适用于简单的 Python 领域语言。

    SQL 数据库的行为不像对象集合,越大和性能越重要; 对象集合的行为越不像表和行,抽象越重要。

    SQLAlchemy 旨在适应这两个原则。 SQLAlchemy 认为数据库是一个关系代数引擎,而不仅仅是一个表的集合。 行不仅可以从表中选择,还可以从连接和其他选择语句中选择; 这些单元中的任何一个都可以组成一个更大的结构。 SQLAlchemy 的表达式语言从其核心建立在这个概念之上。 SQLAlchemy以其对象关系映射器(ORM)而闻名,这是一个提供数据映射器模式的可选组件,其中类可以以开放式、多种方式映射到数据库——允许对象模型和数据库模式在一个 从一开始就干净地解耦。 SQLAlchemy 解决这些问题的整体方法与大多数其他 SQL 完全不同。这是官网的介绍。看起来还是很强大的。

    SQLAlchemy 是一个功能强大的Python ORM 工具包,口碑不错,社区活跃也较为开放所以我们今天就来聊一聊SqlAlchemy,Alchemy是炼金术的意思,看到没名字就这么硬气。

    无论什么语言,无论什么库,做一个ORM实现,至少应当实现完全语义化的数据库操作,使得操作数据库表就像在操作对象。完整的ORM应当可以完全避免SQL拼接

     一般来说SQLAlchemy的使用方式有两种: Core和ORM
    两种有什么不同呢?

    ORM是构建在Core之上的
    Core更加底层, 可以执行直接执行SQL语句
    ORM类似于Django的ORM, 由于sqlalchemy提供了一套接口, 所以不需要我们直接写SQL语句 (1.x版本)
    至于要用哪个, 等到你用到时, 你会知道的

    组件依赖关系

    Core

    一般来说, 使用步骤如下:

    1. 配置数据库连接
    2. 建立连接
    3. 创建表
    4. 执行SQL语句, 按需开启事件是否自动提交
    5. 拿到返回数据, 执行其他代码

    这种方式使用的不多,这里主要使用的是ORM的方式

    ORM方式

    📚 基本概念

    相关概念 

    对应数据库说明
    Engine连接
    Session连接池、事务查询的连接会话 进行数据库操作到对象
    Model类定义和表定义类似,类实例本质上是其中一行
    Column在各个地方支持运算操作
    Query若干行

    可链式操作添加条件:

    1.查看展开成Select

    2.删除展开成Delete

    3.改展开成Update

    概念不多而且很清晰明了,当我们理解好这些概念之后,我们基本就能看出,这里包括了我们常用的大部分操作了。

    Session的作用

    下面是session的一些常见的方法

    方法参数描述
    addinstance下次刷新操作,将instance保存到数据库中
    deleteinstance下次刷新操作,将instance从数据库中删除
    begin

    subtransactions     

    nested _subtrans

    开始事务
    rollback回滚当前事务
    commit提交当前事务
    close

    关闭此session

    execute

    statement 

    params 

    execution_option 

    bind_arguments 等

    执行sql表达式构造
    query

    *entities 

    **kwargs

    返回Query对象 可用于查询数据
    refresh

    instance

    attribute_names with_for_update 

    为instance执行刷新操作

     

    模型定义

    下面我们来看一个如何定义一个模型:

    1. # coding=utf-8
    2. from __future__ import unicode_literals, absolute_import
    3. from sqlalchemy.ext.declarative import declarative_base
    4. from sqlalchemy import Column, Integer, String, DateTime
    5. ModelBase = declarative_base() #<-元类
    6. class User(ModelBase):
    7. __tablename__ = "auth_user"
    8. id = Column(Integer, primary_key=True)
    9. date_joined = Column(DateTime)
    10. username = Column(String(length=30))
    11. password = Column(String(length=128))
    12. # 初始化数据库连接:
    13. engine = create_engine('mysql+mysqlconnector://root:root@localhost:3306/python_db')
    14. # 创建DBSession类型:
    15. DBSession = sessionmaker(bind=engine)

    从这里可以看到,模型定义甚至与数据库是无关的,所以允许不同的数据库后端,不同类型拥有不同的表现形式和建表语句

    这里我们可以看到它实现了 ORM与数据库连接的解耦,一些数据库后端不支持的数据类型,例如Numeric类型,在sqlite中不支持,不过SQLAlchemy也能做一些兼容使用普通浮点

    Model 等同于数据库的一张表
    Column 显然就是这张表的一列

    create_engine()用来初始化数据库连接。SQLAlchemy用一个字符串表示连接信息:

    '数据库类型+数据库驱动名称://用户名:口令@机器地址:端口号/数据库名'

    以上代码完成SQLAlchemy的初始化和具体每个表的class定义。如果有多个表,就继续定义其他class,例如School:

    1. class School(ModelBase):
    2. __tablename__ = 'school'
    3. id = ...
    4. name = ...

    你只需要根据需要替换掉用户名、口令等信息即可。

    下面,我们看看如何向数据库表中添加一行记录。

    增加

    由于有了ORM,我们向数据库表中添加一行记录,可以视为添加一个User对象:

    1. # 创建session对象:
    2. session = DBSession()
    3. # 创建新User对象:
    4. new_user = User(id='5', name='Bob')
    5. # 添加到session:
    6. session.add(new_user)
    7. # 提交即保存到数据库:
    8. session.commit()
    9. # 关闭session:
    10. session.close()

    这时user表就有了bob的一条记录

    可见,关键是获取session,然后把对象添加到session,最后提交并关闭。DBSession对象可视为当前数据库连接。

    get_session底下configure可以控制auto_commit参数,= False时写操作默认都不放在事务里,SQLAlchemy默认为True

    session.add函数将会把Model加入当前的持久空间(可以从session.dirty看到),直到commit时更新

    查询 

    如何从数据库表中查询数据呢?有了ORM,查询出来的可以不再是tuple,而是User对象。SQLAlchemy提供的查询接口如下:

    1. with get_session() as session:
    2. #
    3. session.query(User)

    最简单的这个查询返回了一个Query对象
    需要注意的是,这里只构造Query,事实上并没有发送至数据库进行查询,只会在Query.get()、Query.all()、Query.one()以及Query.__iter__等具有“执行”语义的函数,才会真的去获取 ,如下方法

    1. # 创建Session:
    2. session = DBSession()
    3. # 创建Query查询,filter是where条件,最后调用one()返回唯一行,如果调用all()则返回所有行:
    4. user = session.query(User).filter(User.id=='5').one()
    5. # 打印类型和对象的name属性:
    6. print('type:', type(user))
    7. print('name:', user.name)
    8. # 关闭Session:
    9. session.close()

    加入.one()方法之后,这里就能获取到查询的对象信息了,否则不加的话就是使用的sql语句 

     

     

    可见,ORM就是把数据库表的行与相应的对象建立关联,互相转换。

    由于关系数据库的多个表还可以用外键实现一对多、多对多等关联,相应地,ORM框架也可以提供两个对象之间的一对多、多对多等功能。

    例如,如果一个User拥有多个Book,就可以定义一对多关系如下:

    1. class User(Base):
    2. __tablename__ = 'user'
    3. id = Column(String(20), primary_key=True)
    4. name = Column(String(20))
    5. # 一对多:
    6. books = relationship('Book')
    7. class Book(Base):
    8. __tablename__ = 'book'
    9. id = Column(String(20), primary_key=True)
    10. name = Column(String(20))
    11. # “多”的一方的book表是通过外键关联到user表的:
    12. user_id = Column(String(20), ForeignKey('user.id'))

    当我们查询一个User对象时,该对象的books属性将返回一个包含若干个Book对象的list。

    Query :本质上是数据表的若干行

    1. 在查询情况的下,等同于SQL 中的 SELECT Syntax
    2. 在update函数的操作时,可以根据参数选择等同于直接UPDATE users SET xxx WHERE name=xxx或者先用SELECT 选出ID,再循环用UPDATE xxx WHERE id=xxx
    3. delete同上

    以SQLAlchemy为代表的ORM基本都支持链式操作。

    1. with get_session() as session:
    2. #
    3. query = (session
    4. .query(User)
    5. .filter(User.username == "asd")
    6. .filter_by(username="asd")
    7. #上面两个都是添加where
    8. .join(Addreess)#使用ForeignKey
    9. .join(Addreess,Addreess.user_id==User.id)#使用显式声明
    10. .limit(10)
    11. .offset(0)
    12. )

    所有Query支持的详情见Query API文档

    上面也涉及到一个特别有意思的filter函数:User.username == "asd" ,实际上是SQLAlchemy重载了Column上的各种运算符 __eq__、__ge__,返回了一个BinaryExpression对象,看起来就更加符合直觉上的语义

    复杂查询

    基于Query的subquery

    1. with get_session() as session:
    2. #
    3. query = (session
    4. .query(User.id)
    5. .filter(User.name == "asd")
    6. .filter_by(name="asd")
    7. .limit(10)
    8. )
    9. subquery = query.subquery()
    10. query2 = session.query(User).filter(
    11. User.id.in_(subquery)
    12. )
    13. print query2#<-打印展开成的SQL,此处没有SQL查询

    查询结果的处理:

    all()返回由表对象组成的列表
    first()返回第一个结果 (表对象), 内部执行limit SQL
    one()只返回一行数据或引发异常

    无数据时抛出: sqlalchemy.exc.NoResultFound,

    多行数据时抛出: sqlalchemy.exc.MultipleResultsFound

    one_or_none()最多返回一行数据或引发异常

    无数据时返回None,

    多行数据时抛出: sqlalchemy.exc.MultipleResultsFound

    scalar()获取第一行的第一列数据. 如果没有要获取的行, 则返回None, 多行数据时抛出: sqlalchemy.exc.MultipleResultsFound


    返回由表对象组成的列表



    只返回一行数据或引发异常 (无数据时抛出: sqlalchemy.exc.NoResultFound, 多行数据时抛出: sqlalchemy.exc.MultipleResultsFound)

    最多返回一行数据或引发异常 ()
    scalar()
    获取第一行的第一列数据. 如果没有要获取的行, 则返回None, 多行数据时抛出: sqlalchemy.exc.MultipleResultsFound
     

    删除操作

    删除操作就是先查询出对象,通过该对象再删除就Ok了, 一般形式为: session.query(...).filter(...).delete()

    1. # 删除操作
    2. user = session.query(
    3. User) \
    4. .filter(User.id == 50) \
    5. .delete()
    6. session.commit()
    7. session.close()
    8. print(user)
    1
    

     

    这时只剩下一个了id是50 的大bob就删除了

    像Core一样删除数据, 即delte(...).where(...)

     

    更新操作

    主要步骤是先查询再更新, 即: session.query(...).filter(...).update(...)

    user = session.query(User).filter(User.id == 5).update({"name": 'tom'})

    同样和Core一样, 使用update(...).where(...).values(...)的形式更新数据

    📒扩展与深入进阶

    这里说说1.x和2.x方法的一些区别

    图一

    图二 

    如果觉得本文对你有帮助,欢迎点赞,欢迎关注我,如果有补充欢迎评论交流,我将努力创作更多更好的文章。创作不易,给博主点个小心心吧

     

  • 相关阅读:
    《CTF攻防世界web题》之我什么都不会(1)
    设计问卷调查有哪些技巧?
    学会Python开发的第一步:写一个桌面小程序
    (附源码)spring boot新闻管理系统 毕业设计 211113
    Linux MMC子系统 - 2.eMMC 5.1总线协议浅析
    如何消除左递归、何时需要消除左递归—编译原理
    数据结构入门-14-排序
    四维图新用户大会|CEO程鹏:极致性价比时代,我们能为汽车智能化提供什么?
    node_fs模块常用API
    Golang实现一个批量自动化执行树莓派指令的软件(6)简易批量指令处理
  • 原文地址:https://blog.csdn.net/qq_29235677/article/details/126259494