【问题标题】:How to query a nested attribute in SQLModel?如何查询 SQLModel 中的嵌套属性?
【发布时间】:2022-08-16 16:13:08
【问题描述】:

我有这两个表名为User 和UserRole。

    class UserRoleType(str, enum.Enum):
        admin = \'admin\'
        client = \'client\'
    
    
    class UserRole(SQLModel, table=True):
        __tablename__ = \'user_role\'
        id: int | None = Field(default=None, primary_key=True)
    
        type: UserRoleType = Field(
            default=UserRoleType.client,
            sa_column=Column(Enum(UserRoleType)),
        )
    
        write_access: bool = Field(default=False)
        read_access: bool = Field(default=False)
    
        users: List[\'User\'] = Relationship(back_populates=\'user_role\')
    
    class User(SQLModel, table=True):
        id: int | None = Field(default=None, primary_key=True)
        username: str = Field(..., index=True)
    
        user_role_id: int = Field(..., foreign_key=\'user_role.id\')
        user_role: \'UserRole\' = Relationship(back_populates=\'users\')

我可以轻松地将它们插入数据库:

       async with get_session() as session:
            role = UserRole(description=UserRoleType.client)
            session.add(role)
            await session.commit()
           
            user = User( username=\'test\', user_role_id=role.id)
            session.add(user)
            await session.commit()
            await session.refresh(user)

并通过以下方式访问提交的数据:

          results = await session.execute(select(User).where(User.id == 1)).one()

输出:

     (User(user_role_id=1, username=\'test\', id=1),)

请注意,有一个user_role_id,但user_role 对象在哪里?事实上,如果我尝试访问它,它会引发:

*** AttributeError: Could not locate column in row for column \'user_role\'

我还尝试在插入User 时传递role 而不是user_role_id:

user = User( username=\'test\', user_role=role)

但我得到了:

sqlalchemy.exc.InterfaceError: (sqlite3.InterfaceError) Error binding parameter 2 - probably unsupported type.
  • 您如何尝试访问 user_role ?

标签: python sqlalchemy sqlmodel


【解决方案1】:

先说几件事。

  1. 您没有包含您的导入语句,所以我不得不猜测一些事情。
  2. 您可能希望User.user_role_id 和User.user_role 字段是“pydantically”可选的。这允许您在不将角色传递给构造函数的情况下创建用户实例,让您可以选择在初始化后执行此操作,或者例如将User 对象附加到UserRole.users 列表中。强制用户必须在数据库级别具有角色,您只需在 User.user_role_id 字段上定义 nullable=False。这样,如果您尝试提交到数据库而没有以任何可能的方式为用户定义用户角色,您将收到错误消息。
  3. 在你的数据库插入代码中你写role = UserRole(description=UserRoleType.client)。我假设 description 来自较旧的代码,而您打算编写 role = UserRole(type=UserRoleType.client)。
  4. 您可能希望您的UserRole.type 在数据库端不可为空。您可以通过将nullable=False 传递给Column 构造函数(不是Field 构造函数)。
  5. 我将通过使用阻塞代码(非异步)和 SQLite 数据库进行一些简化。

这应该有效:

from enum import Enum as EnumPy
from sqlalchemy.sql.schema import Column
from sqlalchemy.sql.sqltypes import Enum as EnumSQL
from sqlmodel import Field, Relationship, Session, SQLModel, create_engine


class UserRoleType(str, EnumPy):
    admin = 'admin'
    client = 'client'


class UserRole(SQLModel, table=True):
    __tablename__ = 'user_role'

    id: int | None = Field(default=None, primary_key=True)
    type: UserRoleType = Field(default=UserRoleType.client, sa_column=Column(EnumSQL(UserRoleType), nullable=False))
    write_access: bool = Field(default=False)
    read_access: bool = Field(default=False)

    users: list['User'] = Relationship(back_populates='user_role')


class User(SQLModel, table=True):
    __tablename__ = 'user'

    id: int | None = Field(default=None, primary_key=True)
    username: str = Field(..., index=True)

    user_role_id: int | None = Field(foreign_key='user_role.id', default=None, nullable=False)
    user_role: UserRole | None = Relationship(back_populates='users')


def test() -> None:
    # Initialize database & session:
    sqlite_file_name = 'user_role.db'
    sqlite_url = f'sqlite:///{sqlite_file_name}'
    engine = create_engine(sqlite_url)
    SQLModel.metadata.drop_all(engine)
    SQLModel.metadata.create_all(engine)
    session = Session(engine)

    # Create the test objects:
    role = UserRole(type=UserRoleType.client)
    user = User(username='test', user_role=role)
    session.add(user)
    session.commit()
    session.refresh(user)

    # Do some checks:
    assert isinstance(user.user_role.type, EnumPy)
    assert user.user_role_id == role.id and isinstance(role.id, int)
    assert role.users == [user]


if __name__ == '__main__':
    test()

PS:我知道这个问题是不久前发布的,但也许这仍然有助于或帮助其他人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-02
    • 2022-11-10
    相关资源
    最近更新 更多