Heim > Backend-Entwicklung > Python-Tutorial > Implementieren des Active Record Pattern in Python mit SQLModel

Implementieren des Active Record Pattern in Python mit SQLModel

Mary-Kate Olsen
Freigeben: 2025-01-27 00:12:09
Original
425 Leute haben es durchsucht

Implementing the Active Record Pattern in Python with SQLModel

Python-Entwickler vermissen bei der Migration von Ruby on Rails zu Python oft die elegante Datenbankinteraktion von Active Record. Während Pythons SQLAlchemy (und damit SQLModel) standardmäßig einen anderen Ansatz verfolgt, können wir ein ähnliches Muster implementieren, um den Komfort von Modellen im Rails-Stil in Python-Anwendungen zu integrieren und gleichzeitig die Typsicherheit zu wahren und die Best Practices von Python zu befolgen.

Aktiver Aufnahmemodus

Das Active Record-Muster (populär gemacht durch Ruby on Rails) behandelt Datenbankdatensätze als Objekte mit Datenbankmanipulationsmethoden. Es ist nicht erforderlich, eine separate Repository-Klasse oder ein Datenzugriffsobjekt (DAO) zu verwenden, das Modell selbst weiß, wie es mit der Datenbank interagiert.

Zum Beispiel könnten Sie in Rails schreiben:

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

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

# 创建新记录
post = Post.create(title: "Hello World")</code>
Nach dem Login kopieren

SQLModel in Python verwenden

Obwohl Pythons SQLModel diesen Modus nicht direkt bereitstellt, können wir ihn mithilfe einer Basisklasse implementieren, die diese allgemeinen Operationen bereitstellt. So geht's:

  1. CRUD-basiertes Modell

Zuerst erstellen wir eine Basisklasse, die gängige CRUD-Operationen implementiert:

<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>
Nach dem Login kopieren
  1. Verwenden Sie dieses Muster in Ihrem Modell

Nachdem wir die Basisklasse definiert haben, können wir Modelle erstellen, die sie erben:

<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>
Nach dem Login kopieren
  1. Modell verwenden

Jetzt können wir eine Rails-ähnliche Syntax verwenden, um unsere Modelle zu nutzen und gleichzeitig die explizite Sitzungsverwaltung von Python beizubehalten:

<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>
Nach dem Login kopieren

Hauptunterschiede zu Rails

Während dieses Muster Rails-ähnliche Annehmlichkeiten für Python bietet, sind einige wichtige Unterschiede zu beachten:

  1. Explizite Sitzungsverwaltung: Python erfordert eine explizite Sitzungsverwaltung, die hilft, Datenbanktransaktionen besser zu verstehen.
<code class="language-python"># 使用SQLModel的Python
with get_session() as session:
    article = Article.create(session, title="Hello")

# 与Rails对比
article = Article.create(title: "Hello")</code>
Nach dem Login kopieren
  1. Typsicherheit: Pythons Typhinweise bieten eine bessere IDE-Unterstützung und erkennen Fehler früher.
<code class="language-python">class Article(CRUDModel, table=True):
    title: str  # 类型安全!
    views: int = Field(default=0)</code>
Nach dem Login kopieren
  1. Klassenmethode: Python verwendet einen expliziten @classmethod-Dekorator, um Vorgänge abzuwickeln, die keine Instanz erfordern.
  2. Fehlerbehandlung: Python fördert die explizite Ausnahmebehandlung:
<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>
Nach dem Login kopieren

Best Practices

Beachten Sie bei der Verwendung dieses Musters in Python die folgenden Best Practices:

  1. Verwenden Sie immer den Kontextmanager :
<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>
Nach dem Login kopieren
  1. Typensicherheit:
<code class="language-python">   # 使用正确的类型提示
   def get_article(id: str) -> Optional[Article]:
       with get_session() as session:
           return Article.find(session, id)</code>
Nach dem Login kopieren
  1. Verifizierung:
<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>
Nach dem Login kopieren
  1. Beziehungsmanagement:
<code class="language-python">   class Article(CRUDModel, table=True):
       # 正确使用级联删除
       comments: List["Comment"] = Relationship(
           back_populates="article",
           sa_relationship_kwargs={"cascade": "all, delete-orphan"}
       )</code>
Nach dem Login kopieren

Fazit

Das Active Record-Muster kann effizient in Python implementiert werden, wobei die Typsicherheit gewahrt bleibt und die Best Practices von Python befolgt werden. Obwohl es eine explizitere Sitzungsverwaltung erfordert als Rails, bietet es einen ähnlichen Komfort und gibt Entwicklern gleichzeitig mehr Kontrolle über Datenbankvorgänge.

Dieser Modus eignet sich besonders für:

  • Das Team, das von Rails auf Python migriert ist
  • Elemente, die modellzentrierte Datenbankoperationen bevorzugen
  • Anwendungen, bei denen Typsicherheit und explizite Sitzungsverwaltung wichtig sind

Denken Sie daran, dass dies nur eine Möglichkeit ist, Datenbankoperationen in Python durchzuführen. SQLModel und SQLAlchemy unterstützen andere Modi wie Repositorys oder Datenzugriffsobjekte, die für bestimmte Anwendungsfälle möglicherweise besser geeignet sind.

Ressourcen

  • SQLModel-Dokumentation
  • FastAPI mit SQLModel
  • SQLAlchemy-Dokumentation
  • Geben Sie Hinweise in Python ein

Das obige ist der detaillierte Inhalt vonImplementieren des Active Record Pattern in Python mit SQLModel. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage