参考:

https://www.jianshu.com/p/2c6c76f94b88

https://madmalls.com/blog/post/followers-and-followeds/

实现粉丝机制

1.用户拥有自己的粉丝列表,可以查看自己的粉丝

2.用户拥有自己的关注列表,可以查看自己关注了谁

站在“我”的角度,我的粉丝和我关注的人都来自于User表,我们使用自引用多对多关系(Self-Referential Many-to-Many Relationship)来描述这个模型:

现在我们把视角切换到第三人称(或者说上帝视角),我们面前有两类人:left_users 和 right_users 。根据图片我们这样来描述:

1.站在上帝视角,我们看到 left_users 可以关注 right_users

2.相对的,可以看到 right_users 粉丝是 left_users

这里我们用一个中间表(mid_table)来储存这种关系

数据库模型

mid_table = Table(
'mid_table',Base.metadata,
Column('left_user_id',Integer,ForeignKey('users.id'),primary_key=True),
Column('right_user_id',Integer,ForeignKey('users.id'),primary_key=True)
) class User(Base):
__tablename__='users'
id = Column(Integer,primary_key=True)
name = Column(String) right_users = relationship(
'User',
secondary='mid_table',
primaryjoin=(mid_table.c.left_user_id == id),
secondaryjoin=(mid_table.c.right_user_id == id),
backref = 'left_users'
)

1. right_users:表示 left_users 关注的人,换个说法:左边列表关注了右边列表,此处的 right_users 代表右边列表。

说明一下,左边、右边的列表里面都是实体(如下图所示),而实际中间表里面则是user_id。(*可能理解有误)

2. secondary = 'mid_table' :指定中间表(或者说关联表)

3. primaryjoin=(mid_table.c.left_user_id == id) :  user.right_users 会使用这个条件,表示查询到user关注了谁。如何解释括号内的表达式呢?   *这里在之后的详细实现部分来说明

4. secondaryjoin=(mid_table.c.right_user_id == id) :  user.left_users 会使用这个条件,表示查询user的粉丝是谁。

5. backref = 'left_users' : 反向引用属性,我们用user.right_users来查询user关注了谁,用user.left_users来查询user的粉丝是谁。

详细实现

from sqlalchemy import create_engine,Column,Integer,String,ForeignKey,Table,Text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship,sessionmaker Base = declarative_base()
engine = create_engine('sqlite:///many_many.db',echo=False)
Session = sessionmaker(bind=engine)
session = Session() mid_table = Table(
'mid_table',Base.metadata,
Column('left_user_id',Integer,ForeignKey('users.id'),primary_key=True),
Column('right_user_id',Integer,ForeignKey('users.id'),primary_key=True)
)
def insert(name):
user = User(name = name)
session.add(user)
print('inser ok ...') class User(Base):
__tablename__='users'
id = Column(Integer,primary_key=True)
name = Column(String) right_users = relationship(
'User',
secondary='mid_table',
primaryjoin=(mid_table.c.left_user_id == id),
secondaryjoin=(mid_table.c.right_user_id == id),
backref = 'left_users'
)
def is_followed(self,user):
'''current_user是否关注了user这个用户,网上多是flask-sqlalchemy实现,所以我自己写了一下'''
print(
session.query(mid_table).filter(mid_table.c.left_user_id== self.id)\
.filter(mid_table.c.right_user_id == user.id).count()
)
def following(self,user):
'''关注user这个用户'''
self.right_users.append(user) def __repr__(self):
return "User:name=%s" % self.name

[ 1.初始化数据库 ]

if __name__=='__main__':
Base.metadata.create_all(engine)

 [ 2.向数据库新增用户信息 ]

if __name__=='__main__':
insert("aaa")
insert("bbb")
insert("ccc")
insert("ddd")
session.commit()

检查数据库已经成功添加

[ 3.让用户1关注用户2,用户3关注用户2 ]

if __name__=='__main__':
user1 = session.query(User).get(1)
user2 = session.query(User).get(2)
#让用户3关注用户2
# user3 = session.query(User).get(3)
# user2 = session.query(User).get(2)
user1.following(user2)
session.commit()

这时候查看中间表(mid_table)

结合这里的中间表来解释一下 数据库模型-3 的疑问:

要查询到user关注了谁,为什么primaryjoin括号里面的表达式要这么写(mid_table.c.left_user_id == id)?

可以这样想:结合开头的图,中间表从左到右描述的是 left_user_id 关注了谁,那么我们只需要根据 left_user_id 筛选出 user1,不就可以知道user1关注了谁了么。也就是这样(中间表的left_user_id  == user1的id)

[ 4.查询user1关注了谁 ]

if __name__=='__main__':
user1 = session.query(User).get(1)
print(
user1.right_users
)

结合上面的中间表,得出user1关注了user2,返回的结果自然是user2

执行 user1.right_users 这一句的时候,使用了relathionship里面定义的条件表达式 primaryjoin=(mid_table.c.left_user_id == id) ,因此能够查询出user1关注了谁。

[ 5.查询user2的粉丝是谁 ]

if __name__=='__main__':
user2 = session.query(User).get(2)
print(
user2.left_users
)

有了之前的基础,再结合中间表,要查询user2的粉丝就很简单了,只需要反查就行。

结尾:看了下官方文档和一些博客,感觉有点云里雾里,决定自己写一篇理理头绪,想尽可能形象的来说明。限于能力有限,文章中可能会有很多错误,欢迎指出

[ SQLAlchemy ] 自我引用型的多对多关系(Self-Referential Many-to-Many Relationship)理解的更多相关文章

  1. 用SQLAlchemy创建一对多,多对多关系表

    多对多关系表的创建: 如果建立好多对多关系后,我们就可以通过关系名进行循环查找,比如laowang = Teacher.query.filter(Teacher.name=='laowang').fi ...

  2. 数据库表间多对多关系(附带额外字段)的实体类(POJO 或 POCO)表示

    介绍 在之前的 Entity Framework 快速上手介绍 之中,两个实体之间只是简单的一对一关系,而在实际的应用场景中,还会出现多对多关系,同时还有可能会出现多对多关系还附带有其他字段的情况. ...

  3. python3 + flask + sqlalchemy +orm(3):多对多关系

    一篇文章有多个tag,一个tag也可以属于多篇文章,文章和tag存在多对多关系 config.py DEBUG = True #dialect+driver://root:1q2w3e4r5t@127 ...

  4. SQLAlchemy_定义(一对一/一对多/多对多)关系

    目录 Basic Relationship Patterns One To Many One To One Many To Many Basic Relationship Patterns 基本关系模 ...

  5. jango 模型管理数据model,数据库外键主键与一对一,一对多,多对多关系

    四.models.py 定义和管理模型: 4.1模型class的属性就映射与数据库的字段参数 继承models.Model class TestClass(models.Model): 4.2在数据库 ...

  6. 【极力分享】[C#/.NET]Entity Framework(EF) Code First 多对多关系的实体增,删,改,查操作全程详细示例【转载自https://segmentfault.com/a/1190000004152660】

      [C#/.NET]Entity Framework(EF) Code First 多对多关系的实体增,删,改,查操作全程详细示例 本文我们来学习一下在Entity Framework中使用Cont ...

  7. 《Entity Framework 6 Recipes》翻译系列 (5) -----第二章 实体数据建模基础之有载荷和无载荷的多对多关系建模

    2-3 无载荷(with NO Payload)的多对多关系建模 问题 在数据库中,存在通过一张链接表来关联两张表的情况.链接表仅包含连接两张表形成多对多关系的外键,你需要把这两张多对多关系的表导入到 ...

  8. hibernate学习(5)——多对多关系映射

    1.创建实体和映射 package com.alice.hibernate03.vo; import java.util.HashSet; import java.util.Set; public c ...

  9. EF里一对一、一对多、多对多关系的配置

    EF关系规则 参考文章:http://www.cnblogs.com/feigao/p/4617442.html Entity Framework 实体间的关系,一对一,一对多,多对多,根据方向性来说 ...

随机推荐

  1. 1945-祖安say hello-string

    1 #include<bits/stdc++.h> 2 char str[100][40]; 3 char s[1005]; 4 5 int remark[2000][2] = { 0 } ...

  2. 2020KCTF秋季赛签到题

    比赛平台:https://ctf.pediy.com/game-season_fight-158.htm 开场 签到题 例行检查,64位程序,无壳 试运行一下,看看大概的情况 64位ida载入,根据运 ...

  3. 资源分配(Project)

    <Project2016 企业项目管理实践>张会斌 董方好 编著 资源设置好以后,不能光摆着看,分配到各任务中去才是正道. 分配资源就需要回到与任务相关的视图了,比如[任务工作表]视图或者 ...

  4. Java中List排序的3种方法

    在某些特殊的场景下,我们需要在 Java 程序中对 List 集合进行排序操作.比如从第三方接口中获取所有用户的列表,但列表默认是以用户编号从小到大进行排序的,而我们的系统需要按照用户的年龄从大到小进 ...

  5. 小迪安全 Web安全 基础入门 - 第三天 - 抓包&封包&协议&APP&小程序&PC应用&WEB应用

    一.抓包工具 1.Fiddler.Fiddler是一个用于HTTP调试的代理服务器应用程序,能捕获HTTP和HTTPS流量,并将其记录下来供用户查看.它通过使用自签名证书实现中间人攻击来进行日志记录. ...

  6. JetBrains又出神器啦!Fleet,体验飞一般的感觉

    目录 简介 从eclipse到Fleet Fleet的特性 JetBrains Space 总结 简介 java开发的同学可能对于JetBrains这家公司并不陌生,因为JetBrains号称拥有世界 ...

  7. tcp十种状态;关于tcp中time_wait状态(2MSL问题)

    tcp十种状态 注意: 当一端收到一个FIN,内核让read返回0来通知应用层另一端已经终止了向本端的数据传送 发送FIN通常是应用层对socket进行关闭的结果 关于tcp中time_wait状态的 ...

  8. 有个奇怪的问题,配置成/system/index,jsp页面时没有经过过滤器进行拦截,而配置成redirectAction时是可以直接跳转刀片loginJsp.action

    有个奇怪的问题,配置成/system/index,jsp页面时没有经过过滤器进行拦截,而配置成redirectAction时是可以直接跳转刀片loginJsp.action 但是我直接访问/syste ...

  9. 使用react搭建组件库:react+typescript+storybook

    前期准备 1. 初始化项目 npx create-react-app react-components --template typescript 2. 安装依赖 使用哪种打包方案:webpack/r ...

  10. go实现pdf电子签名-自动识别签名位置

    一. 技术选型 由于要识别签名位置,所以得要能解析pdf的文本布局,要能得到每个布局元素的文本位置坐标.而最终的签名需要合成到pdf上,所以还需要有编辑pdf的需求. pdf布局分析:pdfminer ...