如何实现双向好友关系在各自用户好友列表中正确展示?
问题描述
开发类似Facebook的好友功能,支持发送好友请求、接受后互为好友,但目前无法实现双向好友展示——用户A与B成为好友后,无法互相出现在对方的好友列表中,当前逻辑仅能单向展示(要么显示add_to关联用户,要么显示added_from关联用户),需要基于现有add_to和added_from属性实现双向展示。
现有代码实现
models.py
class AddToNetwork(models.Model): NETWORK_CHOICES = ( ('ADD', 'Add'), ('ACCEPT', 'Accept'), ('DELETE', 'Delete'), ) id = models.UUIDField( primary_key = True, default = uuid.uuid4,editable = False) add_to = models.ForeignKey(User, on_delete=models.CASCADE, related_name="add_to", null=True, blank=True) added_from = models.ForeignKey(User, on_delete=models.CASCADE, related_name="add_from", null=True, blank=True) network_status = models.CharField(max_length=30, choices = NETWORK_CHOICES) added_at = models.DateTimeField(auto_now_add = True) deleted_at = models.DateTimeField(auto_now = True) def __str__(self): return str(self.add_to)
发送好友请求视图
def addToNetwork(request, id): try: add_to = User.objects.get(id = id) current_user = User.objects.get(id = request.user.id) network = AddToNetwork.objects.create(add_to = add_to, added_from=current_user,network_status = 'ADD') messages.success(request,f'Request Sent to {add_to.first_name} {add_to.last_name}') return redirect('userProfileDetail', id) except User.DoesNotExist: add_to = None return render(request,'network/network_userProfile.html')
接受好友请求视图
def acceptNetworkRequest(request, id): try: friend_request = AddToNetwork.objects.get(id = id) friend_request.network_status = 'ACCEPT' friend_request.save() messages.success(request, f'You accepted {friend_request.added_from.first_name} as a friend!') return redirect('friends', id) except AddToNetwork.DoesNotExist: return render(request,'network/friendRequestList.html')
好友列表展示视图
def friends(request, id): user = User.objects.get(id = request.user.id) if user: approved_friends = AddToNetwork.objects.filter(Q(added_from_id = user),network_status = 'ACCEPT') context = { 'friends': approved_friends, } return render(request, 'friend_list.html', context)
好友列表模板
{% for friend in friends %} <tr> <td>{{friend.add_to.first_name}} {{friend.add_to.last_name}}</td> </tr> {% endfor %}
User模型
class User(AbstractUser): username = None id = models.UUIDField( primary_key = True, default = uuid.uuid4,editable = False) first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) email = models.CharField(max_length=50, unique=True) created_at = models.DateTimeField(auto_now_add = True) updated_at = models.DateTimeField(auto_now = True) friends = models.ManyToManyField("self", blank=True)
解决方案
1. 修正好友列表查询逻辑
当前查询仅覆盖了「当前用户是请求发送方」的情况,漏掉了「当前用户是请求接收方」的场景。通过Q查询同时包含两种情况,再提取对应的好友用户:
from django.db.models import Q def friends(request, id): current_user = request.user # 查询所有已通过的好友关系:要么当前用户是发送方,要么是接收方 approved_relations = AddToNetwork.objects.filter( Q(added_from=current_user, network_status='ACCEPT') | Q(add_to=current_user, network_status='ACCEPT') ) # 提取好友对象,避免重复 friends = [] for relation in approved_relations: friend = relation.add_to if relation.added_from == current_user else relation.added_from if friend not in friends: friends.append(friend) context = { 'friends': friends, } return render(request, 'friend_list.html', context)
2. 调整模板显示
现在friends是直接的User对象列表,模板可以简化:
{% for friend in friends %} <tr> <td>{{friend.first_name}} {{friend.last_name}}</td> </tr> {% endfor %}
3. 可选:利用User模型的ManyToMany字段优化
如果希望查询更高效,可以在接受请求时同步更新friends多对多关系,后续查询好友列表会更简洁:
修改接受请求视图:
def acceptNetworkRequest(request, id): try: friend_request = AddToNetwork.objects.get(id = id) friend_request.network_status = 'ACCEPT' friend_request.save() # 同步更新双向好友关系 requester = friend_request.added_from receiver = friend_request.add_to requester.friends.add(receiver) receiver.friends.add(requester) messages.success(request, f'You accepted {requester.first_name} as a friend!') return redirect('friends', request.user.id) except AddToNetwork.DoesNotExist: return render(request,'network/friendRequestList.html')
此时好友列表视图可简化为:
def friends(request, id): current_user = request.user friends = current_user.friends.all() context = { 'friends': friends, } return render(request, 'friend_list.html', context)
内容的提问来源于stack exchange,提问作者djangodeveloper
相关产品推荐
相关产品推荐

