[英]Access backref on relationship when filtering in SQLAlchemy
我有一個名為表ExtendedUser
,有一個人跟一個關系User
與名為backref表extended_user
在User
表。 該User
表有一個與許多關系UserPosts
表與backref命名posts
在User
表。
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
開始,我想選擇所有User
沒有帖子的ExtendedUser
。 所以我嘗試失敗的是
sess.query(ExtendedUser).filter(not_(ExtendedUser.user.posts.any()))
但這不起作用,我得到一個錯誤:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with ExtendedUser.user has an attribute 'posts'
如何為查詢建模,以便僅返回User
擁有UserPost
的ExtendedUser
?
發生錯誤是因為.user
屬性是不同的東西,具體取決於您是從類還是從類的實例訪問它。 例如,這引發了您得到的異常:
ExtendedUser.user.posts
這是因為在類ExtendedUser
上訪問.user
返回InstrumentedAttribute
對象,而InstrumentedAttribute
實例沒有名為posts
屬性。
這有效:
inst = ExtendedUser()
inst.user.posts
上面的方法起作用是因為我們已經在ExtendedUser
實例上訪問了.user
,該實例返回了User
實例 ,該實例具有名為posts
的屬性。
類和實例屬性訪問之間的這種不同行為是由Python的描述符協議控制的。
實現目標的一種方法是使用子查詢在user_posts
表中查詢唯一的user_id
,並測試結果中是否沒有ExtendedUser
的user_id
:
q = sess.query(ExtendedUser).\
filter(
not_(
ExtendedUser.user_id.in_(
sess.query(UserPost.user_id).distinct()
)
)
)
以下是一個有效的示例,但首先我必須稍微更改ExtendedUser.user
的定義:
class ExtendedUser(Base):
...
user = relationship(
"User", backref=backref("extended_user", uselist=False), lazy="joined")
注意使用的backref
功能,讓我設置uselist=False
的User.extended_user
。 您的示例在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)]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.