最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Python 數(shù)據(jù)庫(kù)管理ORM 的終極形態(tài)?

2023-06-07 15:10 作者:程序員-王堅(jiān)  | 我要投稿

ORM

大家都知道ORM(Object Relational Mapping)是一種將對(duì)象和關(guān)系數(shù)據(jù)庫(kù)中的表進(jìn)行映射的技術(shù),它可以讓開(kāi)發(fā)者更加方便地操作數(shù)據(jù)庫(kù),而不用直接使用SQL語(yǔ)句。

直接使用SQL語(yǔ)句操作數(shù)據(jù)庫(kù),雖然可以讓開(kāi)發(fā)者直接與數(shù)據(jù)庫(kù)打交道,但手動(dòng)編寫(xiě)SQL語(yǔ)句,容易出錯(cuò),而且靈活性上比較欠缺。相比之下,使用ORM(以SQLAlchemy為例)有更加易于使用、更加靈活、能防止?SQL?注入攻擊、更加易于測(cè)試的優(yōu)勢(shì)。

點(diǎn)擊查看優(yōu)勢(shì)說(shuō)明

當(dāng)然,使用?SQLAlchemy?也會(huì)增加代碼的復(fù)雜度,需要學(xué)習(xí)額外的知識(shí)和 API。因此,在實(shí)際應(yīng)用中需要根據(jù)具體情況進(jìn)行選擇。

那么有沒(méi)有一種技術(shù)或者框架?既不用增加太多的應(yīng)用成本,又兼具以SQLAlchemy為代表的ORM 框架的優(yōu)勢(shì)?呢?答案是肯定的,那就是我們今天介紹的主角?sqlmodel.

我們就以?Fastapi?開(kāi)發(fā)創(chuàng)建用戶查詢用戶?兩個(gè)功能的接口來(lái)對(duì)比一下 ,SQLAlchemy?和?sqlmodel,?sqlmodel?和 只使用?SQL的差異。

使用SQLAlchemy

安裝

pip install sqlalchemy

示例代碼

from fastapi import FastAPI, Depends, HTTPExceptionfrom sqlalchemy import create_engine, Column, Integer, Stringfrom 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: intclass UserOut(Base): ? ?id: int ? ?name: str ? ?age: intclass UserUpdate(Base): ? ?name: Optional[str] = None ? ?age: Optional[int] = NoneBase.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_userdef 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_userdef 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?是數(shù)據(jù)模型類的名稱,id、name、age?是表中的列名。UserIn?是創(chuàng)建用戶的請(qǐng)求參數(shù)模型,UserOut?是查詢用戶的響應(yīng)數(shù)據(jù)模型,UserUpdate?是更新用戶的請(qǐng)求參數(shù)模型。

使用?create_engine?函數(shù)創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接引擎,使用?sessionmaker?函數(shù)創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)會(huì)話工廠,使用?declarative_base?函數(shù)創(chuàng)建一個(gè)基類。在創(chuàng)建表時(shí),使用?Base.metadata.create_all?函數(shù)創(chuàng)建表。

使用?get_db?函數(shù)獲取數(shù)據(jù)庫(kù)會(huì)話對(duì)象,使用?create_user?和?read_user?函數(shù)進(jìn)行數(shù)據(jù)庫(kù)操作。在視圖函數(shù)中,只需要調(diào)用這些函數(shù)即可完成相應(yīng)的業(yè)務(wù)邏輯。

上面的代碼已經(jīng)非常簡(jiǎn)潔直觀,但是還是有有一定的學(xué)習(xí)成本,下面我們來(lái)看下使用我們今天的主角 --?sqlmodel?需要怎樣來(lái)實(shí)現(xiàn)上面的接口。

使用sqlmodel

安裝 sqlmodel

pip install sqlmodel

示例代碼

點(diǎn)擊查看完整代碼

SQLAlchemy的主要使用差異在參數(shù)的定義上,使用多處繼承,而不是各自定義的方法:

# Code above omitted ??...class UserBase(SQLModel): ? ?name: Optional[str] = None ? ?age: Optional[int] = Noneclass User(UserBase, table=True): ? ?id: Optional[int] = Field(default=None, primary_key=True)class UserIn(UserBase): ? ?passclass UserOut(UserBase): ? ?id: intclass UserUpdate(UserBase): ? ?pass...# Code below omitted ??

繼承這一點(diǎn)對(duì)于還在頻繁迭代的系統(tǒng)中非常重要,因?yàn)橥瑯犹砑?一個(gè)user的數(shù)據(jù)結(jié)構(gòu),SQLAlchemy需要修改4處地方,而sqlmodel?僅僅只需要修改一處。如果有多個(gè)表,這個(gè)便利性的優(yōu)勢(shì)會(huì)尤為突出。

這也就引出了sqlmodel具有的優(yōu)勢(shì):

  • 簡(jiǎn)短:?最小化代碼重復(fù)。一個(gè)單一的類型注解做了很多工作。無(wú)需在 SQLAlchemy 和?Pydantic?中復(fù)制模型。

  • 簡(jiǎn)單易用:?API 設(shè)計(jì)簡(jiǎn)單易用,強(qiáng)大的編輯器支持,學(xué)習(xí)曲線較低,可以快速上手。它使用 Python 類型注解來(lái)定義數(shù)據(jù)模型,可以自動(dòng)推斷數(shù)據(jù)庫(kù)表結(jié)構(gòu),同時(shí)支持類型檢查和數(shù)據(jù)驗(yàn)證。

  • 可擴(kuò)展:?擁有?SQLAlchemy?和?Pydantic?的所有功能。

  • 高性能:?sqlmodel?采用了一些性能優(yōu)化策略,比如使用預(yù)編譯 SQL 語(yǔ)句、減少數(shù)據(jù)庫(kù)連接次數(shù)等,可以提高數(shù)據(jù)庫(kù)操作的性能。

  • 支持異步操作:?sqlmodel?支持異步操作,可以與 asyncio 庫(kù)一起使用,可以在高并發(fā)場(chǎng)景下提高程序的性能。

  • 支持原生 SQL:?sqlmodel?支持原生 SQL,可以使用原生 SQL 語(yǔ)句進(jìn)行數(shù)據(jù)庫(kù)操作,同時(shí)還支持參數(shù)綁定和 SQL 注入防護(hù)。

SQLModel 實(shí)際上是在 Pydantic 和 SQLAlchemy 之間增加了一層兼容適配,經(jīng)過(guò)精心設(shè)計(jì)以兼容兩者。SQLModel 旨在簡(jiǎn)化 FastAPI 應(yīng)用程序中與 SQL 數(shù)據(jù)庫(kù)的交互。它結(jié)合了 SQLAlchemy 和 Pydantic,并嘗試盡可能簡(jiǎn)化代碼,讓代碼重復(fù)減少到最低限度,同時(shí)盡可能讓開(kāi)發(fā)人員獲得最佳的開(kāi)發(fā)體驗(yàn)。

原生的SQL語(yǔ)句支持舉例

有時(shí)候我們可能需要使用原生的SQL語(yǔ)句來(lái)進(jìn)行一些復(fù)雜的操作。

from sqlmodel import create_engine, Session# 創(chuàng)建數(shù)據(jù)庫(kù)引擎engine = create_engine("sqlite:///example.db")# 創(chuàng)建Session對(duì)象with Session(engine) as session: ? ?# 執(zhí)行原生的SQL語(yǔ)句 ? ?result = session.execute("SELECT * FROM users WHERE age > :age", {"age": 18}) ? ?# 處理查詢結(jié)果 ? ?for row in result: ? ? ? ?print(row)

高級(jí)用法:結(jié)合mixin類,簡(jiǎn)化數(shù)據(jù)庫(kù)操作

結(jié)合mixin類,簡(jiǎn)化數(shù)據(jù)庫(kù)操作,一處封裝,處處適用。

如果熟悉fastapi,且仔細(xì)觀察上面的完整代碼就會(huì)發(fā)現(xiàn),除了下面這段,其他的都是標(biāo)準(zhǔn)的Fastapi?接口開(kāi)發(fā)需要的信息。而這樣的操作結(jié)合我們接下來(lái)介紹的mixin方法,就可以給這只虎添上翅膀。

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

tips: 在面向?qū)ο缶幊讨?,Mixin是一種重用代碼的方式,它是一個(gè)類,包含一些方法和屬性,可以被其他類繼承和使用。Mixin類通常不是獨(dú)立的類,而是用于增強(qiáng)其他類的功能。Mixin類的優(yōu)點(diǎn)在于可以將代碼分解為小的、可重用的部分,從而減少代碼的重復(fù)和冗余。Mixin類可以被多個(gè)類繼承,從而避免了多重繼承的問(wèn)題。

import uvicornfrom typing import Optional, Unionfrom fastapi import FastAPI, Depends, HTTPExceptionfrom sqlmodel import Field, Session, SQLModel, create_engine, selectclass 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] = Noneclass User(UserBase, ActiveRecord, table=True): ? ?id: Optional[int] = Field(default=None, primary_key=True) ? ?__table_args__ = {'extend_existing': True}class UserIn(UserBase): ? ?passclass UserOut(UserBase): ? ?id: intclass UserUpdate(UserBase): ? ?pass# 注意:需要提前安裝pymysql, pip install pymysqlSQLALCHEMY_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)

總結(jié)

使用SQLModel?+?mixins可以在公共的邏輯里面實(shí)現(xiàn)增刪改查操作,處封裝,處處適用,減少了代碼的重復(fù)性和冗余性。

特點(diǎn)SQLAlchemysqlmodel數(shù)據(jù)庫(kù)支持支持多種數(shù)據(jù)庫(kù),包括MySQL、PostgreSQL、SQLite等支持多種數(shù)據(jù)庫(kù),包括MySQL、PostgreSQL、SQLite等ORM功能提供全面的ORM功能,支持對(duì)象關(guān)系映射、事務(wù)處理、查詢構(gòu)建等提供輕量級(jí)的ORM功能,支持對(duì)象關(guān)系映射、查詢構(gòu)建等性能性能較好,支持緩存、連接池等優(yōu)化手段性能較好,支持緩存、連接池等優(yōu)化手段學(xué)習(xí)難度學(xué)習(xí)曲線較陡峭,需要掌握復(fù)雜的概念和API學(xué)習(xí)曲線較平緩,易于上手和使用文檔和社區(qū)支持提供完善的文檔和活躍的社區(qū)支持文檔和社區(qū)支持相對(duì)較少代碼規(guī)范代碼規(guī)范較為靈活,可以自由組織代碼結(jié)構(gòu)代碼規(guī)范較為嚴(yán)格,需要按照規(guī)范組織代碼結(jié)構(gòu)

建議:

根據(jù)上述比較,我們可以得出以下選擇建議:

  • 如果需要使用全面的ORM功能,或者需要使用復(fù)雜的查詢構(gòu)建和事務(wù)處理等功能,建議選擇SQLAlchemy。

  • 如果需要使用輕量級(jí)的ORM功能,或者需要快速上手和使用,建議選擇sqlmodel。

  • 如果需要支持多種數(shù)據(jù)庫(kù),建議兩者都可以考慮使用。

  • 如果對(duì)文檔和社區(qū)支持有較高的要求,建議選擇SQLAlchemy。

  • 如果對(duì)代碼規(guī)范有較高的要求,建議選擇sqlmodel。


Python 數(shù)據(jù)庫(kù)管理ORM 的終極形態(tài)?的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
博野县| 安丘市| 古交市| 宜良县| 乐安县| 常山县| 客服| 盐城市| 仪陇县| 永新县| 博客| 报价| 开平市| 乌兰察布市| 滦平县| 隆化县| 昌邑市| 景洪市| 肇东市| 固安县| 垣曲县| 鲁山县| 嵩明县| 仁怀市| 克什克腾旗| 天津市| 那坡县| 广河县| 沂南县| 醴陵市| 连山| 泸州市| 都安| 昭苏县| 阿拉善右旗| 高密市| 石屏县| 大连市| 涟水县| 廊坊市| 贵州省|