【Python】sqlmodel: Python 数据库管理ORM 的终极形态?

这篇具有很好参考价值的文章主要介绍了【Python】sqlmodel: Python 数据库管理ORM 的终极形态?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

ORM

大家都知道ORM(Object Relational Mapping)是一种将对象和关系数据库中的表进行映射的技术,它可以让开发者更加方便地操作数据库,而不用直接使用SQL语句。

直接使用SQL语句操作数据库,虽然可以让开发者直接与数据库打交道,但手动编写SQL语句,容易出错,而且灵活性上比较欠缺。相比之下,使用ORM(以SQLAlchemy为例)有更加易于使用、更加灵活、能防止 SQL 注入攻击、更加易于测试的优势。

点击查看优势说明

更加易于使用: 可以使用 Python 对象来表示数据库中的表和行,而不是直接使用 SQL 语句。这样可以使代码更加易于编写和维护。
更加灵活: SQLAlchemy 提供了灵活的查询语言,可以通过链式调用的方式构建复杂的查询语句。同时,SQLAlchemy 支持多种数据库,可以在不同的数据库之间进行切换,而不需要修改代码。
防止 SQL 注入攻击: SQLAlchemy 提供了参数化查询的方式,可以有效地防止 SQL 注入攻击。使用参数化查询可以将用户输入的数据转换为参数,从而避免了 SQL 注入攻击。
更加易于测试: 使用 SQLAlchemy 可以将业务逻辑和数据库操作分离,从而使得代码更加易于测试。可以通过 Mock 对象模拟数据库操作,从而进行单元测试和集成测试。
...

当然,使用 SQLAlchemy 也会增加代码的复杂度,需要学习额外的知识和 API。因此,在实际应用中需要根据具体情况进行选择。

那么有没有一种技术或者框架 既不用增加太多的应用成本,又兼具以SQLAlchemy为代表的ORM 框架的优势 呢?答案是肯定的,那就是我们今天介绍的主角 sqlmodel.

我们就以 Fastapi 开发创建用户查询用户 两个功能的接口来对比一下 ,SQLAlchemysqlmodelsqlmodel 和 只使用 SQL的差异。

使用SQLAlchemy

安装

pip install sqlalchemy

示例代码

from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import Session, declarative_base, sessionmaker

SQLALCHEMY_DATABASE_URL = "mysql://user:password@host:port/database"

engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

app = FastAPI()

class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String(50))
    age = Column(Integer)

class UserIn(Base):
    name: str
    age: int

class UserOut(Base):
    id: int
    name: str
    age: int

class UserUpdate(Base):
    name: Optional[str] = None
    age: Optional[int] = None

Base.metadata.create_all(bind=engine)

def get_db():
    db = None
    try:
        db = SessionLocal()
        yield db
    finally:
        db.close()

def create_user(db: Session, user: UserIn):
    db_user = User(name=user.name, age=user.age)
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

def read_user(db: Session, user_id: int):
    db_user = db.query(User).filter(User.id == user_id).first()
    if not db_user:
        raise HTTPException(status_code=404, detail="User not found")
    return db_user

def read_all_user(db: Session, ):
    db_user = db.query(User).all()
    if not db_user:
        raise HTTPException(status_code=404, detail="User not found")
    return db_user

@app.post("/users/", response_model=UserOut)
async def create_user_view(user: UserIn, db: Session = Depends(get_db)):
    return create_user(db, user)

@app.get("/users/{user_id}", response_model=UserOut)
async def read_user_view(user_id: int, db: Session = Depends(get_db)):
    return read_user(db, user_id)

@app.get("/users/", response_model=UserOut)
async def read_all_user_view(db: Session = Depends(get_db)):
    return read_all_user(db)

代码解释

User 是数据模型类的名称,idnameage 是表中的列名。UserIn 是创建用户的请求参数模型,UserOut 是查询用户的响应数据模型,UserUpdate 是更新用户的请求参数模型。

使用 create_engine 函数创建一个数据库连接引擎,使用 sessionmaker 函数创建一个数据库会话工厂,使用 declarative_base 函数创建一个基类。在创建表时,使用 Base.metadata.create_all 函数创建表。

使用 get_db 函数获取数据库会话对象,使用 create_userread_user 函数进行数据库操作。在视图函数中,只需要调用这些函数即可完成相应的业务逻辑。

上面的代码已经非常简洁直观,但是还是有有一定的学习成本,下面我们来看下使用我们今天的主角 -- sqlmodel 需要怎样来实现上面的接口。

使用sqlmodel

安装 sqlmodel

pip install sqlmodel

示例代码


点击查看完整代码
# -*- coding: utf-8 -*-
"""
@File   :dda.py
@Date   :2023-06-05
@user   :bingoHe
"""
from typing import Optional

from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from sqlmodel import SQLModel, Field, create_all, Session as SQLModelSession

SQLALCHEMY_DATABASE_URL = "mysql://user:password@host:port/database"

engine = create_engine(SQLALCHEMY_DATABASE_URL)

app = FastAPI()

class UserBase(SQLModel):
    name: Optional[str] = None
    age: Optional[int] = None

class User(UserBase, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)

class UserIn(UserBase):
    pass

class UserOut(UserBase):
    id: int

class UserUpdate(UserBase):
    pass


create_all(engine)

def get_db():
    """获取数据库会话对象"""
    db = None
    try:
        db = SQLModelSession(engine)
        yield db
    finally:
        db.close()

def create_user(db: SQLModelSession, user: UserIn):
    """创建用户"""
    db_user = User.from_orm(user)
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

def read_user(db: SQLModelSession, user_id: int):
    """查询用户"""
    db_user = db.get(User, user_id)
    if not db_user:
        raise HTTPException(status_code=404, detail="User not found")
    return db_user

@app.post("/users/", response_model=UserOut)
async def create_user(user: UserIn, db: SQLModelSession = Depends(get_db)):
    """创建用户"""
    return create_user(db, user)

@app.get("/users/{user_id}", response_model=UserOut)
async def read_user(user_id: int, db: SQLModelSession = Depends(get_db)):
    """查询用户"""
    return read_user(db, user_id)

SQLAlchemy的主要使用差异在参数的定义上,使用多处继承,而不是各自定义的方法:

# Code above omitted 👆
...
class UserBase(SQLModel):
    name: Optional[str] = None
    age: Optional[int] = None

class User(UserBase, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)

class UserIn(UserBase):
    pass

class UserOut(UserBase):
    id: int

class UserUpdate(UserBase):
    pass
...
# Code below omitted 👇

继承这一点对于还在频繁迭代的系统中非常重要,因为同样添加 一个user的数据结构,SQLAlchemy需要修改4处地方,而sqlmodel 仅仅只需要修改一处。如果有多个表,这个便利性的优势会尤为突出。

这也就引出了sqlmodel具有的优势:

  • 简短: 最小化代码重复。一个单一的类型注解做了很多工作。无需在 SQLAlchemy 和 Pydantic 中复制模型。
  • 简单易用: API 设计简单易用,强大的编辑器支持,学习曲线较低,可以快速上手。它使用 Python 类型注解来定义数据模型,可以自动推断数据库表结构,同时支持类型检查和数据验证。
  • 可扩展: 拥有 SQLAlchemyPydantic 的所有功能。
  • 高性能sqlmodel 采用了一些性能优化策略,比如使用预编译 SQL 语句、减少数据库连接次数等,可以提高数据库操作的性能。
  • 支持异步操作: sqlmodel 支持异步操作,可以与 asyncio 库一起使用,可以在高并发场景下提高程序的性能。
  • 支持原生 SQL: sqlmodel 支持原生 SQL,可以使用原生 SQL 语句进行数据库操作,同时还支持参数绑定和 SQL 注入防护。

SQLModel 实际上是在 Pydantic 和 SQLAlchemy 之间增加了一层兼容适配,经过精心设计以兼容两者。SQLModel 旨在简化 FastAPI 应用程序中与 SQL 数据库的交互。它结合了 SQLAlchemy 和 Pydantic,并尝试尽可能简化代码,让代码重复减少到最低限度,同时尽可能让开发人员获得最佳的开发体验。

原生的SQL语句支持举例

有时候我们可能需要使用原生的SQL语句来进行一些复杂的操作。

from sqlmodel import create_engine, Session

# 创建数据库引擎
engine = create_engine("sqlite:///example.db")

# 创建Session对象
with Session(engine) as session:
    # 执行原生的SQL语句
    result = session.execute("SELECT * FROM users WHERE age > :age", {"age": 18})

    # 处理查询结果
    for row in result:
        print(row)

高级用法:结合mixin类,简化数据库操作

结合mixin类,简化数据库操作,一处封装,处处适用。

如果熟悉fastapi,且仔细观察上面的完整代码就会发现,除了下面这段,其他的都是标准的Fastapi 接口开发需要的信息。而这样的操作结合我们接下来介绍的mixin方法,就可以给这只虎添上翅膀。
class User(UserBase, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)

tips: 在面向对象编程中,Mixin是一种重用代码的方式,它是一个类,包含一些方法和属性,可以被其他类继承和使用。Mixin类通常不是独立的类,而是用于增强其他类的功能。Mixin类的优点在于可以将代码分解为小的、可重用的部分,从而减少代码的重复和冗余。Mixin类可以被多个类继承,从而避免了多重继承的问题。

import uvicorn
from typing import Optional, Union

from fastapi import FastAPI, Depends, HTTPException
from sqlmodel import Field, Session, SQLModel, create_engine, select


class ActiveRecord(SQLModel):
    @classmethod
    def by_id(cls, _id: int, session):
        obj = session.get(cls, _id)
        if obj is None:
            raise HTTPException(status_code=404, detail=f"{cls.__name__} with id {id} not found")
        return obj

    @classmethod
    def all(cls, session):
        return session.exec(select(cls)).all()

    @classmethod
    def create(cls, source: Union[dict, SQLModel], session):
        if isinstance(source, SQLModel):
            obj = cls.from_orm(source)
        # elif isinstance(source, dict):
        elif isinstance(source, dict):
            obj = cls.parse_obj(source)
        session.add(obj)
        session.commit()
        session.refresh(obj)
        return obj

    def save(self, session):
        session.add(self)
        session.commit()
        session.refresh(self)


class UserBase(SQLModel):
    name: Optional[str] = None
    age: Optional[int] = None


class User(UserBase, ActiveRecord, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    __table_args__ = {'extend_existing': True}


class UserIn(UserBase):
    pass


class UserOut(UserBase):
    id: int


class UserUpdate(UserBase):
    pass

# 注意:需要提前安装pymysql, pip install pymysql
SQLALCHEMY_DATABASE_URL = "mysql+pymysql://user:password@host:port/database"

engine = create_engine(SQLALCHEMY_DATABASE_URL)


def create_db_and_tables():
    SQLModel.metadata.create_all(engine)


def get_session():
    with Session(engine) as session:
        yield session


app = FastAPI()


@app.on_event("startup")
def on_startup():
    create_db_and_tables()


@app.post("/User/", response_model=UserOut)
def create_user(hero: UserIn, session: Session = Depends(get_session)):
    return User.create(hero, session)

@app.get("/User/", response_model=list[UserOut])
def read_user(session: Session = Depends(get_session)):
    return User.all(session)

@app.get("/User/{user_id}", response_model=UserOut)
def read_user(user_id: int,session: Session = Depends(get_session)):
    return User.by_id(user_id, session)


if __name__ == '__main__':
    uvicorn.run("main:app", reload=True)

总结

使用SQLModel + mixins可以在公共的逻辑里面实现增删改查操作,处封装,处处适用,减少了代码的重复性和冗余性。

特点 SQLAlchemy sqlmodel
数据库支持 支持多种数据库,包括MySQL、PostgreSQL、SQLite等 支持多种数据库,包括MySQL、PostgreSQL、SQLite等
ORM功能 提供全面的ORM功能,支持对象关系映射、事务处理、查询构建等 提供轻量级的ORM功能,支持对象关系映射、查询构建等
性能 性能较好,支持缓存、连接池等优化手段 性能较好,支持缓存、连接池等优化手段
学习难度 学习曲线较陡峭,需要掌握复杂的概念和API 学习曲线较平缓,易于上手和使用
文档和社区支持 提供完善的文档和活跃的社区支持 文档和社区支持相对较少
代码规范 代码规范较为灵活,可以自由组织代码结构 代码规范较为严格,需要按照规范组织代码结构

建议:

根据上述比较,我们可以得出以下选择建议:文章来源地址https://www.toymoban.com/news/detail-473555.html

  • 如果需要使用全面的ORM功能,或者需要使用复杂的查询构建和事务处理等功能,建议选择SQLAlchemy。
  • 如果需要使用轻量级的ORM功能,或者需要快速上手和使用,建议选择sqlmodel。
  • 如果需要支持多种数据库,建议两者都可以考虑使用。
  • 如果对文档和社区支持有较高的要求,建议选择SQLAlchemy。
  • 如果对代码规范有较高的要求,建议选择sqlmodel。

到了这里,关于【Python】sqlmodel: Python 数据库管理ORM 的终极形态?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flutter教程之 Flutter 开发者的终极 Hive 数据库管理工具

    作为 Flutter 开发人员,您知道 Hive 是一个功能强大、轻量级且易于使用的键值数据库,适用于您的 Flutter 应用程序。但是管理 Hive 数据库可能有点棘手,尤其是当您使用多个框和表时。这就是为什么我很高兴地宣布推出Flutter 的原因hive_ui,这是一个新的 Flutter 包,可以让您轻

    2024年02月09日
    浏览(44)
  • Django、数据库----------ORM框架

    目录 1.安装第三方模块 2.ORM 1.自己创建数据库 2.django连接数据库 3.django操作表 创建表:在models.py文件中 删除表以及修改表 在表中新增列时,由于已存在列中可能已有数据,所以新增列必须要指定新增列对应的数据 Django开发操作数据库更简单,内部提供了ORM框架。   ORM可以

    2024年02月09日
    浏览(44)
  • Django ORM:最全面的数据库处理指南

    深度探讨Django ORM的概念、基础使用、进阶操作以及详细解析在实际使用中如何处理数据库操作。同时,我们还讨论了模型深入理解,如何进行CRUD操作,并且深化理解到数据库迁移等高级主题。为了全面解读Django ORM,我们也讨论了其存在的不足,并对其未来发展进行了展望。

    2024年02月13日
    浏览(48)
  • SQLAlchemy ORM指南:简化数据库操作的最佳实践

    背景: ​ SQLAlchemy是一个数据库的ORM框架,让我们操作数据库的时候不要再用SQL语句了,跟直接操作模型一样。操作十分便捷,其实SQLAlchemy应该是在Flask和Django应用的特别多,而且在flask中已经集成了flask_sqlalchemy ,好像是 SQLAlchemy的作者和 Flask是同一个,背景了解到这里就可

    2024年01月20日
    浏览(68)
  • 【1 beego学习 -MAC框架与ORM数据库】

    1,由于在github上安装,所以需要安装git软件,安装过程一直点击下一步即可。安装完成后需要配置环境变量 修改go环境变量 go env -w GO111MODULE=on go env -w GOPROXY=https://goproxy.cn 2,设置GOPATH 环境变量,并且将 GOPATH/bin 加入到了环境变量。 3,安装bee go get -u -v github.com/astaxie/beego go get

    2024年02月11日
    浏览(33)
  • Django创建应用、ORM的进阶使用及模型类数据库迁移

    Django 项目就是基于 Django 框架开发的 Web 应用,它包含了一组配置和多个应用,我们把应用称之为 App,在前文中对它也做了相应的介绍,比如 auth、admin,它们都属于 APP。 一个 App 就是一个 Python 包,通常一个 App 可以包含模型、视图、模板和 URL 配置文件,可以被应用到多个

    2024年02月09日
    浏览(40)
  • Java与数据库:JDBC和ORM框架的使用和效率优化

      随着互联网的快速发展和大数据时代的到来,数据库在软件开发中起到了至关重要的作用。Java作为一门强大而广泛应用的编程语言,提供了多种与数据库交互的方式。其中,JDBC和ORM框架是最常用的两种方式。本文将深入探讨JDBC和ORM框架的使用方法,并分享一些提高效率的

    2024年02月08日
    浏览(30)
  • Django学习记录:使用ORM操作MySQL数据库并完成数据的增删改查

    数据库操作 MySQL数据库+pymysql Django开发操作数据库更简单,内部提供了ORM框架。 安装第三方模块 ORM可以做的事: 1、创建、修改、删除数据库中的表(不用写SQL语句)。【无法创建数据库】 2、操作表中的数据(不用写SQL语句)。 1、自己创建数据库 1)启动MySQL服务 2)自带

    2024年02月14日
    浏览(43)
  • 献给转java的c#和java程序员的数据库orm框架

    一个好的程序员不应被语言所束缚,正如我现在开源java的orm框架一样,如果您是一位转java的c#程序员,那么这个框架可以带给你起码没有那么差的业务编写和强类型体验。如果您是一位java程序员,那么该框架可以提供比 Mybatis-Plus 功能更加丰富、性能更高,更加轻量和完全免费的体

    2024年02月05日
    浏览(29)
  • 梅西生涯数据管理系统(Python+数据库)

    用 Tkinter + MySQL 实现简单的数据分析系统,一起来看看吧! 本篇博客主要分为两大部分,一部分主要是对数据库的操作,另一部分主要是使用Python进行一些程序设计与数据分析。 代码下载地址:https://download.csdn.net/download/m0_68111267/88029856 python tkinter mysql 1. 导入数据 以下是My

    2024年02月08日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包