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

Django邮箱验证功能报错求助:QuerySet精确查找需切片限制

账号邮箱验证功能报错修复方案

错误根源分析

  1. 最初用get()获取用户时报错,是因为你的User模型中email字段没有设置唯一约束,导致数据库存在多个邮箱相同的用户,get()无法返回单个结果。
  2. 改成filter()后出现的The QuerySet value for an exact lookup must be limited to one result using slicing错误,是因为你把User.objects.filter()返回的QuerySet直接传给了EmailVerification.objects.filter(user=user),而外键字段的精确查找要求传入单个对象,不能传QuerySet。

第一步:修复User模型,确保邮箱唯一性

正常业务逻辑中一个邮箱应对应唯一账号,修改User模型的email字段添加唯一约束:

class User(AbstractUser):
    image = models.ImageField(upload_to='users_image', null=True, blank=True)
    is_verified_email = models.BooleanField(default=False)
    # 重写email字段,添加唯一约束
    email = models.EmailField(unique=True)

执行数据库迁移(注意:如果数据库已有重复邮箱的用户记录,需先手动清理再迁移,否则会失败):

python manage.py makemigrations
python manage.py migrate

第二步:修复视图代码

现在可以安全使用get()获取单个用户,同时增加异常处理避免程序崩溃:

class EmailVerificationView(TitleMixin, TemplateView):
    title = 'Store - Подтверждение электронной почты'
    template_name = 'users/email_verification.html'

    def get(self, request, *args, **kwargs):
        code = kwargs['code']
        try:
            # 通过唯一邮箱获取单个用户
            user = User.objects.get(email=kwargs['email'])
            # 获取对应用户和验证码的验证记录
            email_verification = EmailVerification.objects.get(user=user, code=code)
            
            if not email_verification.is_expired():
                user.is_verified_email = True
                user.save()
                return super().get(request, args, **kwargs)
        except (User.DoesNotExist, EmailVerification.DoesNotExist):
            # 用户不存在或验证记录无效,直接跳过
            pass
        
        # 验证过期、无效或其他异常,跳回首页
        return HttpResponseRedirect(reverse('index'))

代码优化点说明

  • 用try-except捕获两种常见异常,避免因用户不存在或验证记录失效导致的程序崩溃
  • 直接用get()获取单个验证记录,替代filter().exists()+first()的写法,逻辑更简洁
  • 去掉冗余的多层判断,代码可读性更高

额外优化建议

建议验证链接用用户ID替代邮箱传递,避免邮箱暴露在URL中,同时防止用户修改邮箱后验证链接失效:

  1. 修改EmailVerification模型的send_verification_email方法:
def send_verification_email(self):
    # 用user_id替代email作为URL参数
    link = reverse('users:email_verification', kwargs={'user_id': self.user.id, 'code': self.code})
    verification_link = f'{settings.DOMAIN_NAME}{link}'
    subject = f'Подтверждение учётной записи для {self.user.username}'
    message = 'Для подтверждения учетной записи для {} перейдите по ссылке: {}'.format(
        self.user.email,
        verification_link)
    send_mail(
        subject=subject,
        message=message,
        from_email=settings.EMAIL_HOST_USER,
        recipient_list=[self.user.email],
        fail_silently=False,
    )
  1. 同步修改视图的参数接收和用户获取逻辑:
def get(self, request, *args, **kwargs):
    code = kwargs['code']
    try:
        user = User.objects.get(id=kwargs['user_id'])
        # 后续逻辑不变...

内容的提问来源于stack exchange,提问作者123321

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 19:23:21