fastapi: sqlalchemy:在model中增加需要查询数据的属性

一,功能说明:

用户表users,用户头像的地址放在assets表中, 需要查询得到:

在异步 SQLAlchemy (AsyncSession) 环境下,由于 Python 的 @property 只能是同步方法,我们绝对不能在 @property 内部使用 await 去执行数据库查询。
在异步架构中,最标准、性能最好的做法是:利用 relationship 配合 selectinload(或 joinedload)在预加载数据后,再通过同步的 @property 或 Pydantic 转换为默认值。

 

所以这个问题的解决稍微麻烦一些,因为需要修改查询条件

在sql中使用 selectinload 预加载关联的 avatar_asset,这一步如果不做,则我们所加的属性会触发异常 :

例如:

'User.avatar_asset' is not available due to lazy='raise'

二,代码:

User类

# 用户模型
class User(MyBaseModel):
    __tablename__ = "users"

    username: Mapped[str] = mapped_column(String(100),server_default="''", comment='用户名')
    nickname: Mapped[str] = mapped_column(String(100), server_default="''", comment='昵称')
    password: Mapped[str] = mapped_column(String(100), server_default="''", comment='密码')

    avatar_id: Mapped[Optional[BigInteger]] = mapped_column(ForeignKey("assets.id"), nullable=True)

    # 1. 建立异步关联关系
    # 使用 lazy="raise" 可以防止在未预加载时误调用导致报错,强迫编写高性能代码
    avatar_asset: Mapped[Optional["Asset"]] = relationship("Asset", lazy="raise")

    # 2. 定义同步 property
    @property
    def avatar_url(self) -> str:
        DEFAULT_AVATAR = "https://example.com/default.png"
        try:
            # 如果已经预加载了关联数据,直接读取
            if self.avatar_asset:
                return self.avatar_asset.full_path
            else:
                return DEFAULT_AVATAR
        except Exception as err:
            # 如果没有预加载(触发了 lazy="raise" 异常),转为返回默认值或抛出特定说明
            print(err)
            return DEFAULT_AVATAR

调用:

            async with AsyncSessionLocal() as db:
                # 1. 查询用户是否存在
                stmt = select(User).where(User.username == current_user['username']).options(selectinload(User.avatar_asset))
                result = await db.execute(stmt)
                user = result.scalar_one_or_none()

                print("user:",user)
                print("avatar_url:", user.avatar_url)

 

posted @ 2026-07-21 12:52  刘宏缔的架构森林  阅读(2)  评论(0)    收藏  举报