Maison >développement back-end >Tutoriel Python >Implémentation du modèle d'enregistrement actif en Python avec SQLModel
Les développeurs Python manquent souvent l'interaction élégante avec la base de données d'Active Record lors de la migration de Ruby on Rails vers Python. Bien que SQLAlchemy de Python (et donc SQLModel) adopte une approche différente par défaut, nous pouvons implémenter un modèle similaire pour apporter la commodité des modèles de style Rails aux applications Python tout en maintenant la sécurité des types et en suivant les meilleures pratiques Python.
Mode d'enregistrement actif
Le modèle Active Record (popularisé par Ruby on Rails) traite les enregistrements de base de données comme des objets avec des méthodes de manipulation de base de données. Il n'est pas nécessaire d'utiliser une classe de référentiel ou un objet d'accès aux données (DAO) distinct, le modèle lui-même sait comment interagir avec la base de données.
Par exemple, dans Rails vous pourriez écrire :
<code class="language-ruby"># 查找记录 user = User.find(123) # 更新记录 user.name = "New Name" user.save # 创建新记录 post = Post.create(title: "Hello World")</code>
Utiliser SQLModel en Python
Bien que le SQLModel de Python ne fournisse pas directement ce mode, nous pouvons l'implémenter en utilisant une classe de base qui fournit ces opérations courantes. Voici comment procéder :
Tout d'abord, nous créons une classe de base qui implémente les opérations CRUD courantes :
<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>
Après avoir défini la classe de base, nous pouvons créer des modèles qui en héritent :
<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>
Nous pouvons désormais utiliser une syntaxe de type Rails pour consommer nos modèles tout en conservant la gestion explicite des sessions de 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>
Principales différences avec Rails
Bien que ce modèle apporte à Python des commodités similaires à celles de Rails, il existe quelques différences importantes à noter :
<code class="language-python"># 使用SQLModel的Python with get_session() as session: article = Article.create(session, title="Hello") # 与Rails对比 article = Article.create(title: "Hello")</code>
<code class="language-python">class Article(CRUDModel, table=True): title: str # 类型安全! views: int = Field(default=0)</code>
@classmethod
explicite pour gérer les opérations qui ne nécessitent pas d'instance. <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>
Bonnes pratiques
Lorsque vous utilisez ce modèle en Python, gardez à l'esprit les bonnes pratiques suivantes :
<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>
<code class="language-python"> # 使用正确的类型提示 def get_article(id: str) -> Optional[Article]: with get_session() as session: return Article.find(session, id)</code>
<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>
<code class="language-python"> class Article(CRUDModel, table=True): # 正确使用级联删除 comments: List["Comment"] = Relationship( back_populates="article", sa_relationship_kwargs={"cascade": "all, delete-orphan"} )</code>
Conclusion
Le modèle Active Record peut être implémenté efficacement en Python tout en maintenant la sécurité des types et en suivant les meilleures pratiques Python. Bien qu'il nécessite une gestion de session plus explicite que Rails, il offre une commodité similaire tout en donnant aux développeurs plus de contrôle sur les opérations de base de données.
Ce mode est particulièrement adapté pour :
N'oubliez pas, ce n'est qu'une méthode de fonctionnement de la base de données dans Python. SqlModel et Sqlalchemy prennent en charge d'autres modes, tels que le référentiel ou les objets d'accès aux données, qui peuvent être plus adaptés à certains cas.
Ressource
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!