I am trying to create a social network, such as matching many to many in SQLAlchemy. That is, I have a character class and a character_relations crosstab to reference from Character to Character. So far, it's easy:
character_relationships = Table('character_relationships', Base.metadata, Column('me_id', Integer, ForeignKey('characters.id', ondelete=True, onupdate=True), nullable=False, primary_key=True), Column('other_id', Integer, ForeignKey('characters.id', ondelete=True, onupdate=True), nullable=False, primary_key=True), UniqueConstraint('me_id', 'other_id', name='uix_1') ) class CharacterRelationship(object): def __init__(self, me_id, other_id): self.me_id = me_id self.other_id = other_id mapper(CharacterRelationship, character_relationships) class Character(IdMixin, TimestampMixin, Base): __tablename__ = "characters" name = Column(Unicode, nullable=False) friends = relationship(lambda: Character, secondary=character_relationships, primaryjoin=lambda: Character.id==character_relationships.c.me_id, secondaryjoin=lambda: Character.id==character_relationships.c.other_id, backref=backref('knows_me') )
There are two possible connections: one-way and two-way. That is, in the crosstab I can have
CharacterRelationship(me_id=1, other_id=2) CharacterRelationship(me_id=2, other_id=1)
The argument to Character.friends above is for one-way relationships. How can I add the / column _property property for two-way relationships?
This my_character.real_friends only contains entries from CharacterRelationship if the relationship is "on both sides."
I know I can use something like
@property def real_friends(self): return set(my_character.friends) & set(my_character.knows_me)
but it doesnβt translate well into sql, and I would expect tremendous speedup to perform this given intersection at the database level. But to achieve even more!
Even better would be to have a destination object like:
character.friends.other_character character.friends.relationship_type = -1 | 0 | 1
Where
- -1 means I know the other one-sidedly,
- 0 double-sided,
- 1 means that others know me unilaterally.
Do you see the reason this logic is at the database level? If so, how would you do it? If you know, do you know how to put a simple two-way part of real_friend at the database level?