在SQLAlchemy中筛选时访问关系的backref

2024-05-17 16:20:30 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个名为ExtendedUser的表,它与User表上的一个backref为extended_userUser表有一对一的关系。User表与UserPosts表有一对多关系,在User表上有一个名为posts的backref。在

class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True)

class UserPost(Base):
    __tablename__ = "user_posts"

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey("users.id"))
    user = relationship("User", backref="posts")

class ExtendedUser(Base):
    __tablename__ = "extended_users"

    user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
    user = relationship("User", backref="extended_user", uselist=False, lazy="joined")

ExtendedUser开始,我想选择所有ExtendedUser,它们的Users没有post。 所以我没能成功

^{pr2}$

但这不起作用,我得到一个错误:

^{3}$

如何对查询建模,以便只有ExtendedUserUser返回{}s?在


Tags: keyidextendedbasecolumnintegerusersclass
1条回答
网友
1楼 · 发布于 2024-05-17 16:20:30

发生错误是因为.user属性是不同的,这取决于您是从类访问它,还是从类的实例访问它。例如,这会引发您正在获取的异常:

ExtendedUser.user.posts

这是因为访问类ExtendedUser上的.user返回一个InstrumentedAttribute对象,InstrumentedAttribute的实例没有名为posts的属性。在

这是有效的:

^{pr2}$

上面的操作是因为我们访问了.user,它返回了User的一个实例,该实例返回了一个名为posts的属性的实例。在

类和实例属性访问之间的这种不同行为是由Python的descriptor protocol控制的。在

实现目标的一种方法是使用子查询来查询user_posts表中唯一的user_id,并测试{}的{}不在结果中:

^{3}$

下面是一个有效的示例,但首先我必须稍微更改ExtendedUser.user的定义:

class ExtendedUser(Base):
    ...
    user = relationship(
        "User", backref=backref("extended_user", uselist=False), lazy="joined")

注意使用了backref函数,它允许我在^{上设置uselist=False。您的示例在ExtendedUser.user上有uselist=False,但由于外键是在ExtendedUser上定义的,所以ExtendedUser.user只能指向一个用户,sqlalchemy会自动知道集合不应该是一个列表。如果没有这个改变,我会得到一个TypeError: Incompatible collection type: ExtendedUser is not list-like异常。在

好的,下面是一个例子:

sess = Session()
user_1 = User(extended_user=ExtendedUser())
user_2 = User(extended_user=ExtendedUser())
user_3 = User(extended_user=ExtendedUser())
user_1.posts = [UserPost()]
sess.add_all([user_1, user_2, user_3])
sess.commit()
q = sess.query(ExtendedUser).\
    filter(
        not_(
            ExtendedUser.user_id.in_(
                sess.query(UserPost.user_id).distinct()
            )
        )
    )

print(q.all())  # [ExtendedUser(user_id=2), ExtendedUser(user_id=3)]

相关问题 更多 >