首頁 > 後端開發 > Python教學 > 使用 SQLModel 在 Python 中實作活動記錄模式

使用 SQLModel 在 Python 中實作活動記錄模式

Mary-Kate Olsen
發布: 2025-01-27 00:12:09
原創
460 人瀏覽過

Implementing the Active Record Pattern in Python with SQLModel

Python開發者從Ruby on Rails遷移到Python時,常常會懷念Active Record的優雅資料庫互動方式。雖然Python的SQLAlchemy(以及SQLModel)預設採用不同的方法,但我們可以實現類似的模式,將Rails風格模型的便利性引入Python應用程序,同時保持類型安全並遵循Python最佳實踐。

Active Record模式

Active Record模式(由Ruby on Rails推廣)將資料庫記錄視為具有資料庫操作方法的物件。它無需使用單獨的儲存庫類別或資料存取物件(DAO),模型本身就知道如何與資料庫互動。

例如,在Rails中,你可以這樣寫:

<code class="language-ruby"># 查找记录
user = User.find(123)

# 更新记录
user.name = "New Name"
user.save

# 创建新记录
post = Post.create(title: "Hello World")</code>
登入後複製

在Python中使用SQLModel實作

雖然Python的SQLModel沒有直接提供這種模式,但我們可以使用一個提供這些常用操作的基底類別來實作它。方法如下:

  1. 基於CRUD的模型

首先,我們建立一個實作常用CRUD運算的基底類別:

<code class="language-python">from typing import TypeVar, List, Optional, Tuple
from datetime import datetime
import uuid
from sqlmodel import SQLModel, Session, select
from sqlalchemy import func

T = TypeVar("T", bound="CRUDModel")

class CRUDModel(SQLModel):
    id: str = Field(
        default_factory=lambda: str(uuid.uuid4()),
        primary_key=True
    )
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)

    @classmethod
    def all(cls: type[T], session: Session) -> List[T]:
        statement = select(cls)
        return session.exec(statement).all()

    @classmethod
    def find(cls: type[T], session: Session, id: str) -> Optional[T]:
        statement = select(cls).where(cls.id == id)
        return session.exec(statement).first()

    @classmethod
    def create(cls: type[T], session: Session, **kwargs) -> T:
        db_obj = cls(**kwargs)
        session.add(db_obj)
        session.commit()
        session.refresh(db_obj)
        return db_obj

    def update(self: T, session: Session, **kwargs) -> T:
        kwargs['updated_at'] = datetime.utcnow()
        for key, value in kwargs.items():
            setattr(self, key, value)
        session.add(self)
        session.commit()
        session.refresh(self)
        return self

    def delete(self: T, session: Session) -> None:
        session.delete(self)
        session.commit()

    @classmethod
    def paginate(
        cls: type[T],
        session: Session,
        page: int = 1,
        per_page: int = 20
    ) -> Tuple[List[T], int]:
        statement = select(cls)
        total = session.exec(select(func.count()).select_from(statement)).one()

        offset = (page - 1) * per_page
        results = session.exec(
            statement.offset(offset).limit(per_page)
        ).all()

        return results, total</code>
登入後複製
  1. 在模型中使用此模式

定義好基底類別後,我們可以建立繼承它的模型:

<code class="language-python">class Article(CRUDModel, table=True):
    title: str = Field(..., description="Article title")
    content: str = Field(..., description="Article content")
    status: str = Field(default="draft")

    # Relationships
    comments: List["Comment"] = Relationship(
        back_populates="article",
        sa_relationship_kwargs={"cascade": "all, delete-orphan"}
    )</code>
登入後複製
  1. 使用模型

現在,我們可以使用類似Rails的語法來使用我們的模型,同時保持Python顯式的會話管理:

<code class="language-python">from db.session import get_session

# 列出所有文章
with get_session() as session:
    articles = Article.all(session)

# 查找特定文章
with get_session() as session:
    article = Article.find(session, "some-uuid")
    if article:
        print(f"Found: {article.title}")

# 创建新文章
with get_session() as session:
    article = Article.create(
        session,
        title="My New Article",
        content="Some content here"
    )

# 更新文章
with get_session() as session:
    article = Article.find(session, "some-uuid")
    if article:
        updated = article.update(
            session,
            title="Updated Title",
            content="New content"
        )

# 删除文章
with get_session() as session:
    article = Article.find(session, "some-uuid")
    if article:
        article.delete(session)

# 分页
with get_session() as session:
    articles, total = Article.paginate(session, page=2, per_page=10)</code>
登入後複製

與Rails的主要差異

雖然這種模式為Python帶來了類似Rails的便利性,但需要注意一些重要的區別:

  1. 明確會話管理: Python需要明確會話管理,這有助於更好地理解資料庫事務。
<code class="language-python"># 使用SQLModel的Python
with get_session() as session:
    article = Article.create(session, title="Hello")

# 与Rails对比
article = Article.create(title: "Hello")</code>
登入後複製
  1. 類型安全: Python的類型提示提供了更好的IDE支持,並能更早地捕獲錯誤。
<code class="language-python">class Article(CRUDModel, table=True):
    title: str  # 类型安全!
    views: int = Field(default=0)</code>
登入後複製
  1. 類別方法: Python使用明確的@classmethod裝飾器來處理不需要實例的操作。
  2. 錯誤處理: Python鼓勵明確異常處理:
<code class="language-python">with get_session() as session:
    try:
        article = Article.find(session, "non-existent")
        if article is None:
            raise HTTPException(status_code=404, detail="Article not found")
    except Exception as e:
        # 处理其他数据库错误
        raise HTTPException(status_code=500, detail=str(e))</code>
登入後複製

最佳實踐

在Python中使用此模式時,請記住以下最佳實踐:

  1. 總是使用上下文管理器:
<code class="language-python">   # 正确的做法
   with get_session() as session:
       article = Article.create(session, title="Hello")

   # 不正确的方法
   session = get_session()
   article = Article.create(session, title="Hello")
   session.close()</code>
登入後複製
  1. 模式安全:
<code class="language-python">   # 使用正确的类型提示
   def get_article(id: str) -> Optional[Article]:
       with get_session() as session:
           return Article.find(session, id)</code>
登入後複製
  1. 驗證:
<code class="language-python">   class Article(CRUDModel, table=True):
       title: str = Field(..., min_length=1, max_length=100)
       status: str = Field(
           default="draft",
           validate_default=True,
           validator=lambda x: x in ["draft", "published"]
       )</code>
登入後複製
  1. 關係管理:
<code class="language-python">   class Article(CRUDModel, table=True):
       # 正确使用级联删除
       comments: List["Comment"] = Relationship(
           back_populates="article",
           sa_relationship_kwargs={"cascade": "all, delete-orphan"}
       )</code>
登入後複製

結論

Active Record模式可以在Python中有效實現,同時保持類型安全並遵循Python最佳實踐。雖然它比Rails需要更明確的會話管理,但它提供了類似的便利性,同時為開發人員提供了對資料庫操作的更多控制。

這種模式特別適用於:

  • 從Rails遷移到Python的隊伍
  • 偏好模型中心資料庫操作的項目
  • 類型安全和明確會話管理很重要的應用程式

請記住,這只是Python中資料庫操作的一種方法。 SQLModel和SQLAlchemy支援其他模式,例如儲存庫或資料存取對象,這些模式可能更適合某些用例。

資源

  • SQLModel文件
  • 使用SQLModel的FastAPI
  • SQLAlchemy文件
  • Python中的型別提示

以上是使用 SQLModel 在 Python 中實作活動記錄模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板