You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:24:20