特に、association proxiesについて知りたいことがあります。アソシエーションプロキシはSQLAlchemyに、追加データを含む可能性のある中間テーブルによって仲介された多対多の関係を持つことを通知します。あなたのケースでは、それぞれUser
は複数のリクエストを送信することができ、また複数のリクエストを受け取ることができ、Relationship
はstatus
列を追加データとして含む仲介テーブルです。ここで
は、あなたが書いたものに比較的近いままあなたのコードの変種です:
from sqlalchemy.ext.associationproxy import association_proxy
class User(db.Model):
__tablename__ = 'User'
# The above is not necessary. If omitted, __tablename__ will be
# automatically inferred to be 'user', which is fine.
# (It is necessary if you have a __table_args__, though.)
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(35), unique=False)
# and so forth
requested_rels = db.relationship(
'Relationship',
foreign_keys='Relationship.requesting_user_id',
backref='requesting_user'
)
received_rels = db.relationship(
'Relationship',
foreign_keys='Relationship.receiving_user_id',
backref='receiving_user'
)
aspiring_friends = association_proxy('received_rels', 'requesting_user')
desired_friends = association_proxy('requested_rels', 'receiving_user')
def __repr__(self):
# and so forth
class Relationship(db.Model):
# __tablename__ removed, becomes 'relationship'
# __table_args__ removed, see below
requesting_user_id = db.Column(db.Integer, db.ForeignKey('User.id'), primary_key=True)
receiving_user_id = db.Column(db.Integer, db.ForeignKey('User.id'), primary_key=True)
# Marking both columns above as primary_key creates a compound primary
# key, which at the same time saves you the effort of defining the
# UNIQUE constraint in __table_args__
status = db.Column(db.Integer)
# Implicit one-to-many relations: requesting_user, receiving_user.
# Normally it would be more convenient to define those relations on
# this side, but since you have two outgoing relationships with the
# same table (User), you chose wisely to define them there.
は(私は少し異なるラインを発注し、確保しながら、どのように私は外部キー列のため_id
接尾辞を使用する方法に注意してくださいdb.relationship
のサフィックスが付いていない同じ名前を使用してください)。
User
から、フレンドリーな着信要求と対応するユーザーに直接アクセスできます。モデル。あなたは、にもjoin
でなければならない場合があります。(私はこれをテストしていない
def get_friends(user):
requested_friends = (
db.session.query(Relationship.receiving_user)
.filter(Relationship.requesting_user == user)
.filter(Relationship.status == CONFIRMED)
)
received_friends = (
db.session.query(Relationship.requesting_user)
.filter(Relationship.receiving_user == user)
.filter(Relationship.status == CONFIRMED)
)
return requested_friends.union(received_friends).all()
:あなたは、ユーザーのすべての確認の友人を得るために以下のコードを記述する必要があるためしかし、これはまだ理想的な未満でありますunion
が動作するためには、両方のクエリでUser
。)
さらに悪いことに、モデル名Relationship
だけでなく、モデル内のいくつかのメンバーの名前は、彼らが実際に何を意味するのか、非常によく伝えていないようです。
Relationship.status
を削除し、Relationship
の名前をFriendshipRequest
に変更して、問題を改善することができます。次いで、Friendship
と呼ばれる第二User
User
-to-アソシエーションモデルを追加し、backref
SおよびUser
にassociation_proxy
Sとdb.Relationship
Sの対応する第2のセットを追加します。誰かが友情要求を送ると、FriendshipRequest
にレコードを提出します。要求が受け入れられた場合は、レコードを削除し、Friendship
の新しいレコードで置き換えます。このように、ステータスコードを使用する代わりに、友だちのステータスは、ユーザーのペアを格納するテーブルによってエンコードされます。 Friendship
モデルは次のようになります。
class Friendship(db.Model):
user1_id = db.Column(db.Integer, db.ForeignKey('User.id'), primary_key=True)
user2_id = db.Column(db.Integer, db.ForeignKey('User.id'), primary_key=True)
# Implicit one-to-many relations: user1, user2
# (defined as backrefs in User.)
(User
にdb.relationship
sおよびassociation_proxy
の対応読者への課題として残されています。)
この方法では、ユーザーの確認済みの友達が必要なときに、フィルタリング操作の半分を節約できます。ただし、Friendship
の各インスタンスでuser1
またはuser2
のいずれかを使用できるため、2つのクエリのうちunion
を作成する必要があります。反射的な対称関係を扱っているため、これは本質的に困難です。私はそれを行うよりエレガントな方法を発明することは可能だと思うが、スタックオーバーフローに関する新たな質問を保証するのに十分複雑であると思う。
「Relationship」テーブルはこの場合の関連テーブルです。 「友人関係」の対称性は、「友情関係」関係の非対称性と直接の不一致である。私はあなたが2つを分けるべきだと思います。 – univerio