sqlalchemy 监听所有实体插入以及更新事件

文章介绍了如何在Flask应用中使用DependencyInjector和SQLAlchemy,创建了一个公共类CommonEntity,通过@event.listens_for监听before_insert和before_update事件,实现了在插入和更新实体时自动更新特定字段,如created_dt,updated_dt和version,简化了数据库操作。

这边使用的是flask+dependency-injecter+sqlalchemy,有一个公共类,想插入或者更新的时候对公共类某些字段进行统一操作

这个是公共类:包括一些基础字段,所有的实体都会继承这个类 

"""Models module."""

from datetime import datetime
from sqlalchemy import Column, String, Integer,DateTime#, Boolean

from sqlalchemy.ext.declarative import declarative_base


Base = declarative_base()

class CommonEntity(Base):
    __abstract__ = True

    created_dt = Column(DateTime)
    created_by = Column(String)
    updated_dt = Column(DateTime)
    updated_by = Column(String)
    version = Column(Integer)

然后是db的配置

"""Database module."""

from contextlib import contextmanager, AbstractContextManager
from typing import Callable

from sqlalchemy import create_engine, orm,event
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session
from datetime import datetime

from main.services.common_service.db_access.domain.common_field_entity import CommonEntity
Base = declarative_base()

class DatabaseConfig:

    def __init__(self, db_url: str) -> None:
        self._engine = create_engine(db_url, echo=True)
        self._session_factory = orm.scoped_session(
            orm.sessionmaker(
                autocommit=False,
                autoflush=False,
                expire_on_commit=False,
                bind=self._engine,
            ),
        )

    def create_database(self) -> None:
        Base.metadata.create_all(self._engine)


    @contextmanager
    def session(self) -> Callable[..., AbstractContextManager[Session]]:
        session: Session = self._session_factory()
        try:
            yield session
        except Exception:
            session.rollback()
            raise
        else:
            if session._transaction.is_active:
                session.commit()
            session.close()

    @event.listens_for(CommonEntity, 'before_insert', propagate=True)
    def before_insert_listener(self, mapper, target):
        # 在创建时自动更新 created_dt,version
        target.created_dt = datetime.now()
        target.created_by = 'Damien'
        target.version = 1
        
    @event.listens_for(CommonEntity, 'before_update', propagate=True)
    def before_update_listener(self, mapper, target):
        # 在更新时自动更新 updated_dt,version
        target.updated_dt = datetime.now()
        target.updated_by = 'Damien'
        target.version += 1

 重要的就是@event.listens_for,这里。监听公共类,所有继承了它的实体的插入更新都会被监听到,然后就是对里面的字段进行统一的操作就行了,不用再每次插入或者更新进行手动修改了

### SQLAlchemy 插入更新操作 #### 使用 `insert()` 和 `update()` 进行基本操作 在 SQLAlchemy 中,`insert()` 和 `update()` 是用于执行插入更新操作的主要方法。这些方法可以在核心层或 ORM 层使用。 对于简单的插入操作,可以创建一个新的实例并将其添加到会话中: ```python from sqlalchemy import create_engine, Column, Integer, String from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String) engine = create_engine('sqlite:///:memory:') Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) session = Session() new_user = User(name='Alice') session.add(new_user) session.commit() ``` 当需要批量插入多个记录时,也可以一次性提交多个对象[^1]: ```python users_to_add = [ User(name='Bob'), User(name='Charlie') ] session.bulk_save_objects(users_to_add) session.commit() ``` 针对更新操作,在 SQLAlchemy 2.0 中推荐的方式之一是通过查询定位要修改的对象,之后更改其属性再保存回数据库: ```python user_to_update = session.query(User).filter_by(name='Alice').first() if user_to_update: user_to_update.name = "Alicia" session.commit() ``` 另一种更高效的方法是在不加载整个实体的情况下直接调用 `update()` 方法来更新特定字段的值: ```python session.query(User).filter(User.id == 1).update({User.name: 'Ally'}) session.commit() ``` 如果想要利用原生 SQL 来完成同样的任务,则可以通过 `text()` 构造器构建自定义语句,并传递给 execute 函数执行[^2]: ```python from sqlalchemy import text stmt = text("UPDATE users SET name=:name WHERE id=:id") result = engine.execute(stmt, {"name": "Alex", "id": 1}) ``` 以上就是关于如何使用 SQLAlchemy 执行插入更新的一些基础介绍以及具体的应用案例[^3].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值