Trong số những điều khác, bạn có thể muốn tìm hiểu về proxy liên kết . Một proxy kết hợp cho SQLAlchemy biết rằng bạn có một mối quan hệ nhiều-nhiều được dàn xếp bởi một bảng trung gian có thể chứa dữ liệu bổ sung. Trong trường hợp của bạn, mỗi User
có thể gửi nhiều yêu cầu và cũng nhận được nhiều yêu cầu và Relationship
là bảng dàn xếp có chứa status
làm dữ liệu bổ sung.
Đây là một biến thể của mã của bạn tương đối gần với những gì bạn đã viết:
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.
(Lưu ý cách tôi sắp xếp các dòng hơi khác một chút và cách tôi sử dụng _id
hậu tố cho các cột khóa ngoại trong khi đặt cùng tên mà không có hậu tố cho db.relationship
tương ứng S. Tôi cũng khuyên bạn nên áp dụng phong cách này.)
Giờ đây, bạn có một cách rõ ràng để truy cập các yêu cầu kết bạn đến và đi cũng như những người dùng tương ứng trực tiếp từ User
của bạn người mẫu. Tuy nhiên, điều này vẫn còn ít lý tưởng hơn vì bạn cần viết mã sau để nhận được tất cả xác nhận bạn bè của người dùng:
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()
(Tôi đã không kiểm tra điều này; bạn cũng có thể cần phải join
với User
trong cả hai truy vấn để cho union
để làm việc.)
Để làm cho mọi thứ tồi tệ hơn, tên mô hình Relationship
cũng như tên của một số thành viên trong mô hình dường như không truyền tải được rõ ràng ý nghĩa thực sự của chúng.
Bạn có thể cải thiện vấn đề bằng cách xóa Relationship.status
và đổi tên Relationship
tới FriendshipRequest
. Sau đó, thêm User
thứ hai -to- User
mô hình liên kết được gọi là Friendship
và thêm tập hợp thứ hai tương ứng gồm db.Relationship
s với backref
s và association_proxy
s tới User
. Khi ai đó gửi yêu cầu kết bạn, bạn gửi hồ sơ tới FriendshipRequest
. Nếu yêu cầu được chấp nhận, bạn xóa bản ghi và thay thế nó bằng một bản ghi mới trong Friendship
. Bằng cách này, thay vì sử dụng mã trạng thái, trạng thái của tình bạn được mã hóa bởi bảng mà bạn lưu trữ một cặp người dùng. Friendship
mô hình có thể trông như thế này:
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.)
(db.relationship
s và association_proxy
s trong User
được để lại như một bài tập cho người đọc.)
Cách tiếp cận này giúp bạn tiết kiệm một nửa số thao tác lọc khi bạn cần những người bạn đã được xác nhận của người dùng. Tuy nhiên, bạn cần tạo union
trong số hai truy vấn vì người dùng của bạn có thể là user1
hoặc user2
trong mỗi trường hợp của Friendship
. Điều này vốn đã khó bởi vì chúng ta đang xử lý mối quan hệ đối xứng phản xạ. Tôi nghĩ rằng vẫn có thể phát minh ra những cách thực hiện tốt hơn, nhưng tôi nghĩ điều đó sẽ đủ phức tạp để đảm bảo một câu hỏi mới ở đây trên Stack Overflow.