DRF:如何从关联模型中排除已投票用户及当前用户ID?
解决Django自关联投票中排除已投票用户与自身的问题
我来帮你搞定这个需求——让登录用户既不能给自己投票,也不能重复投给同一个人。核心思路是在ModelViewSet里动态生成查询集,结合当前用户的已投票记录来过滤掉不符合条件的用户,具体步骤和代码如下:
1. 重写ModelViewSet的get_queryset方法
因为我们需要根据当前登录用户的状态动态调整返回的用户列表,所以不能用静态的queryset属性,必须重写get_queryset方法来实现动态过滤。
2. 获取当前用户与已投票用户ID
在方法里先拿到当前登录的用户,然后通过用户的vote关联字段获取所有已经被投票过的用户ID列表:
self.request.user:获取当前登录的用户对象current_user.vote.values_list('id', flat=True):返回一个扁平的已投票用户ID列表,方便后续排除操作
3. 组合排除条件过滤查询集
使用Django的exclude()方法结合Q对象,同时排除“当前用户自己”和“已投票用户”这两类对象。
完整代码示例
假设你有一个用来展示可投票用户的ViewSet,代码可以写成这样:
from django.db.models import Q from rest_framework import status from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet from rest_framework.permissions import IsAuthenticated from .models import User from .serializers import UserSerializer class VoteCandidateViewSet(ModelViewSet): serializer_class = UserSerializer # 确保只有登录用户才能访问 permission_classes = [IsAuthenticated] def get_queryset(self): current_user = self.request.user # 获取所有已被当前用户投票的用户ID voted_user_ids = current_user.vote.values_list('id', flat=True) # 排除自己 + 已投票用户 return User.objects.exclude( Q(id=current_user.id) | Q(id__in=voted_user_ids) ) # 额外:在创建投票时做后端校验,防止恶意请求 def create(self, request, *args, **kwargs): to_user_id = request.data.get('to_user') current_user = request.user # 校验是否给自己投票 if to_user_id == str(current_user.id): return Response( {"error": "不能给自己投票"}, status=status.HTTP_400_BAD_REQUEST ) # 校验是否已投过该用户 if current_user.vote.filter(id=to_user_id).exists(): return Response( {"error": "已经给该用户投过票了"}, status=status.HTTP_400_BAD_REQUEST ) return super().create(request, *args, **kwargs)
代码说明
Q(id=current_user.id):直接排除当前用户自己,避免出现给自己投票的选项Q(id__in=voted_user_ids):排除所有已经被当前用户投票过的用户,防止重复投票- 后端的
create方法校验是额外的保障:即使前端没有过滤掉非法选项,后端也会拦截非法请求,确保数据的合法性
内容的提问来源于stack exchange,提问作者slqq
相关产品推荐
相关产品推荐

