PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

sqlalchemy đối xứng nhiều thành một tình bạn

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.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tối ưu hóa truy vấn trong PostgreSQL. GIẢI THÍCH Khái niệm cơ bản - Phần 3

  2. flask-migrate không thể thả bảng vì các đối tượng khác phụ thuộc vào nó

  3. PostgreSQL 9.1:Cách nối các hàng trong mảng mà không có bản sao, THAM GIA một bảng khác

  4. PostgreSQL pg_dump

  5. Làm thế nào để chuyển đổi cơ sở dữ liệu trong postgres?