Django创建关注关系后,User关联followers/followings集合为空问题
问题:Django关注关系中反向关联集合为空的排查
我正在开发支持用户互相关注的社交媒体项目,相关模型如下:
django.contrib.auth.models.User
class UsersProfiles(ddm.Model): user = ddm.OneToOneField( dcam.User, on_delete=ddm.CASCADE, related_name="profile", ) followers_count = ddm.IntegerField(default=0) followings_count = ddm.IntegerField(default=0)
class UsersFollows(ddm.Model): follower = ddm.ForeignKey( dcam.User, on_delete=ddm.CASCADE, related_name="followers", ) following = ddm.ForeignKey( dcam.User, on_delete=ddm.CASCADE, related_name="followings", )
为提升扩展性,我通过存储粉丝数和关注数实现数据冗余,而非通过UsersFollows模型计算。使用Django事务保证添加关注操作的原子性:
with ddt.atomic(): umuf.UsersFollows.objects.create( follower=user, following=followed_user, ) followed_user.profile.followers_count += 1 user.profile.followings_count += 1 followed_user.profile.save() user.profile.save()
但测试时发现用户对应的粉丝和关注集合为空:
def test_valid(self): response = self.client.post( c.urls.USERS_1_FOLLOWINGS, {"user": 2}, headers=h.generate_headers(self.login_response), ) h.assertEqualResponses(response, c.responses.SUCCESS) user1 = dcam.User.objects.get(pk=1) user2 = dcam.User.objects.get(pk=2) self.assertEqual(user1.profile.followings_count, 1) self.assertEqual(user2.profile.followers_count, 1) follow = umuf.UsersFollows.objects.filter( follower=user1, following=user2, ) self.assertEqual(len(follow), 1) # 以下两个断言失败 self.assertIn(user1, user2.followers.all()) self.assertIn(user2, user1.followings.all())
我尝试保存两个User实例,也尝试手动保存UsersFollows实例,但问题仍未解决,请问遗漏了什么?
解决方案
问题出在UsersFollows模型的related_name命名逻辑完全搞反了:
related_name的作用是定义反向关联的名称,也就是从关联模型(这里是User)访问当前模型(UsersFollows)记录的属性名。- 你当前的设置中,
follower字段的related_name="followers",意味着user.followers.all()会返回所有以该user为关注者的UsersFollows记录,而不是你期望的「关注该user的人」。 - 同理,
following字段的related_name="followings",会让user.followings.all()返回所有被该user关注的UsersFollows记录的反向?完全不符合你的语义需求。
正确的related_name应该对应业务语义:
- 对于
follower字段(发起关注的用户),反向关联应该是「该用户关注的所有人」,所以related_name设为followings。 - 对于
following字段(被关注的用户),反向关联应该是「所有关注该用户的人」,所以related_name设为followers。
修正后的UsersFollows模型:
class UsersFollows(ddm.Model): follower = ddm.ForeignKey( dcam.User, on_delete=ddm.CASCADE, related_name="followings", # user.followings → 该用户关注的所有人 ) following = ddm.ForeignKey( dcam.User, on_delete=ddm.CASCADE, related_name="followers", # user.followers → 所有关注该用户的人 )
修正后,你的测试断言就能正常通过:
user2.followers.all()会返回所有关注user2的用户(即user1)user1.followings.all()会返回user1关注的用户(即user2)
另外不需要额外保存User实例,因为反向关联的数据是直接从UsersFollows表中查询的,只要记录创建成功,重新查询User实例后就能获取到正确的关联集合。
内容的提问来源于stack exchange,提问作者Aditya
相关产品推荐
相关产品推荐

