如何在Tortoise ORM中实现带额外字段的多对多关联模型
问题1解答
不可以直接用原生add()方法同时指定角色。
Tortoise ORM的多对多add()方法仅会自动填充中间表的两个关联外键字段,不会处理你自定义的额外role字段,所以当role设置了非空约束时就会触发报错。你可以自行给模型封装便捷方法来实现类似add()的调用体验:
class Group(Model): id = fields.IntField(pk=True) name = fields.CharField(max_length=255) members = fields.ManyToManyField("models.User", related_name="groups", through="Membership") def __str__(self): return self.name # 自定义添加成员方法 async def add_member(self, user: User, role: str): # get_or_create避免重复添加同一个用户到同一个组 await Membership.get_or_create(user=user, group=self, defaults={"role": role})
后续调用方式:
await new_group1.add_member(new_user1, role="member")
问题2解答
首先需要先给中间表Membership的外键添加反向关联名,方便后续关联查询:
class Membership(Model): user = fields.ForeignKeyField("models.User", related_name="memberships") group = fields.ForeignKeyField("models.Group", related_name="memberships") role = fields.CharField(max_length=255) class Meta: # 增加联合唯一约束,避免同一个用户重复加入同一个组 unique_together = (("user", "group"),)
查询时使用prefetch_related预加载关联的中间表和用户数据,就可以同时拿到用户信息和对应的角色:
# 预加载中间表和关联用户,避免N+1查询问题 groups = await Group.all().prefetch_related("memberships__user") for group in groups: print(f"用户组:{group.name}") for membership in group.memberships: print(f"用户邮箱:{membership.user.email},角色:{membership.role}")
输出示例:
用户组:group1 用户邮箱:a@a.com,角色:member 用户邮箱:b@b.com,角色:admin 用户组:group2 用户邮箱:a@a.com,角色:member
内容的提问来源于stack exchange,提问作者Kenneth Ban
相关产品推荐
相关产品推荐

