为什么 SQLAlchemy 的 fetchall() 方法不返回与表字段关联的属性?

问题描述 投票:0回答:1

我正在尝试使用

PostgreSQL
SQLAlchemy
async
)从 FastAPI 表中检索数据。这是我的模型:

class LoginHistory(Base):
    __tablename__ = 'login_history'

    id = Column(
        UUID(as_uuid=True), primary_key=True,
        default=uuid.uuid4, unique=True, nullable=False
    )
    user_id = Column(UUID(as_uuid=True), ForeignKey('user.id'))
    user = relationship('User', back_populates='login_history')
    user_agent = Column(String(255))
    login_dt = Column(DateTime)

    def __init__(self, user_id: UUID, user_agent: str, login_dt: datetime) -> None:
        self.user_id = user_id
        self.login_dt = login_dt
        self.user_agent = user_agent

以下是用户服务的片段:

from typing import Annotated

from fastapi import Header, Request
from sqlalchemy import insert, select
from sqlalchemy.ext.asyncio import AsyncSession

from auth.src.models.entity import LoginHistory

async def get_login_history(
    authorization: Annotated[str, Header()],
    db: AsyncSession
) -> dict:
    result = await token_logic.get_token_authorization(authorization)
    if result.get('error'):
        return result
    access_token = result.get('token')
    user_id = await token_logic.get_user_id_by_token(access_token)
    query = select(LoginHistory).where(LoginHistory.user_id == user_id)
    history = await db.execute(query)
    login_history = history.fetchall()
    return {'success': [{
            'user_agent': record.user_agent,
            'login_dt': record.login_dt.isoformat()
    } for record in login_history]
    }

当我提出请求时,我收到错误:

AttributeError: user_agent
。据我了解,
fetchall()
方法应该返回
Row
对象列表,其中包含与表字段关联的属性(在我的例子中,
user_agent
login_dt
等)。我做错了什么?非常感谢您的回复。

我使用的版本:

SQLAlchemy==2.0.16
FastAPI==0.97.0
asyncpg==0.27.0

python async-await sqlalchemy fastapi attributeerror
1个回答
0
投票

问题在于

.fetchall()
返回单元素元组列表,其中每个元素都是
LoginHistory
的实例:

[
    (<__main__.LoginHistory object at 0x7f43764f7590>,),
    (<__main__.LoginHistory object at 0x7f43764f7610>,)
]

所以

record.user_Agent for record in login_history
将会失败,因为元组没有
useragent
属性。

调用

.scalars()
而不是
.fetchall()
可以解决问题,因为
.scalars()
的目的正是从结果中消除包装元组。或者我们可以简单地做

login_history = await session.scalars(query)

并删除多余的

history
变量。

© www.soinside.com 2019 - 2024. All rights reserved.