1

我怎样才能实现一个自我引用的多对多关系,它实际上是两个其他关系的联合?

该关系应返回用户与网络中其他用户之间存在的所有 FacebookFriendship 模型。一个用户可能有一个指向另一个现有用户的 FacebookFriendship,但由于 FB API 中断、隐私控制等原因,现有用户对该用户的镜像 FBFriendship 可能不存在。

# This class is necessary for python-social-auth
# A UserSocialAuth model only exists for users who are in the network
class UserSocialAuth(_AppSession, Base, SQLAlchemyUserMixin):
    """Social Auth association model"""
    __tablename__ = 'social_auth_usersocialauth'
    __table_args__ = (UniqueConstraint('provider', 'uid'),)
    id = Column(Integer, primary_key=True)
    provider = Column(String(32))
    uid = Column(String(UID_LENGTH))
    extra_data = Column(JSONType())
    user_id = Column(
        Integer, ForeignKey(User.id), nullable=False, index=True)
    user = relationship(
        User,
        backref=backref('social_auth', lazy='dynamic')
    )

此关系查找从该用户指向任何现有用户的 FacebookFriendship 模型。

    facebook_friendships = relationship(
        FacebookFriendship,
        primaryjoin=and_(
            user_id == FacebookFriendship.user_id,
            provider == 'facebook'
        ),
        secondary=FacebookFriendship.__table__,
        secondaryjoin=uid == FacebookFriendship.fb_uid_friend,
        foreign_keys=[provider, user_id, uid],
        viewonly=True,
        uselist=True,
        lazy='dynamic',
    )

这种关系会找到指向该用户的 FacebookFriendship 模型。

    other_facebook_friendships = relationship(
        FacebookFriendship,
        primaryjoin=and_(
            uid == FacebookFriendship.fb_uid_friend,
            provider == 'facebook'
        ),
        foreign_keys=[provider, uid],
        viewonly=True,
        uselist=True,
        lazy='dynamic',
    )

我能够使用 hybrid_property 装饰器来表达联合查询,但这会阻止使用像 any() 这样的比较器或使用关联代理,至少从我能说的情况来看是这样。

    # Can I rewrite this using relationship()?
    @hybrid_property
    def all_facebook_friendships(self):
        return self.facebook_friendships.union(
            self.other_facebook_friendships).correlate(
            FacebookFriendship)

# FBFriendship models are created for every friend that a user has,
# regardless of whether they're in the network or not.
class FacebookFriendship(Base):
    __tablename__ = u'user_fb_friend'

    user_id = Column(Integer, sa.ForeignKey(User.id), primary_key=True)

    user = relationship(
        User, backref=backref('facebook_friendships', lazy='dynamic'),
        primaryjoin=User.id == user_id)

    fb_uid_friend = Column(sa.String(length=255), primary_key=True)

最后,我想像任何其他 InstrumentedAttribute: 一样查询这种关系 UserSocialAuth.query.filter(UserSocialAuth.all_facebook_friendships.any()).all() ,并在 User 模型上定义一个 association_proxy:

User.all_facebook_friends = association_proxy('all_facebook_friendships', 'user')

很抱歉这个问题的长度,但我已经试错了几天,但无济于事。

有关的:

4

1 回答 1

1

使用上面链接的 zzzeek 的解决方案,我通过使用 select 语句作为 relationship() 的“辅助”参数创建了一个自我引用的 M2M 关系。

friendship_union = select([
    FacebookFriendship.dater_id,
    cast(FacebookFriendship.fb_uid_friend, Integer()).label(
        'fb_uid_friend')
]).union(
    select([
        cast(FacebookFriendship.fb_uid_friend, Integer()),
        FacebookFriendship.dater_id]
    )
).alias()

cls.all_fb_friendships = relationship(
    UserSocialAuth,
    secondary=friendship_union,
    primaryjoin=UserSocialAuth.user_id == friendship_union.c.dater_id,
    secondaryjoin=and_(
        UserSocialAuth.provider == 'facebook',
        cast(UserSocialAuth.uid, Integer() ) == friendship_union.c.fb_uid_friend,
    ),
    viewonly=True
)
于 2014-06-12T23:58:45.287 回答