Django调用User.get()报MultipleObjectsReturned返回2条数据错误
报错根因
Django ORM的get()方法设计为仅返回1条匹配的查询结果:匹配0条抛出DoesNotExist异常,匹配≥2条就会抛出你遇到的MultipleObjectsReturned异常。
你的代码触发报错的直接原因及关联问题:
- 两处
User.objects.get()调用完全没有传入任何过滤参数,等价于查询User全表数据,只要表中用户数≥2必然触发异常,分别出现在message和getMessages两个视图函数中。 message视图中return render(...)写在用户判断、创建逻辑之前,return之后的代码永远不会执行,属于死代码。User模型的username字段没有加唯一约束,允许重复用户名存入,即使加了过滤条件也可能匹配到多条记录。Message模型的user字段用长字符串存储,没有和User做外键关联,getMessages视图中Message.objects.filter()也没有加过滤条件,会返回全量用户的所有消息,不符合业务预期。- 字段存在拼写错误:
confrom_password应为confirm_password,后续表单校验容易出问题。 - 存在冗余操作:
objects.create()方法已经完成数据库写入,不需要再手动调用实例的save()方法。
修复步骤
1. 修正模型定义
如果是测试环境,建议先清空已有迁移文件和测试数据库,再替换为以下模型代码,避免字段变更导致的迁移冲突:
from django.db import models from datetime import datetime class User(models.Model): member_id = models.BigAutoField(primary_key=True) username = models.CharField(max_length=100, unique=True) # 加唯一约束,从库层面保证用户名不重复 name = models.CharField(max_length=100) email = models.EmailField(max_length=50) password = models.CharField(max_length=100) confirm_password = models.CharField(max_length=50) # 修正拼写错误 class Message(models.Model): value = models.CharField(max_length=10000) # 去掉不合理的超长大数设置 date = models.DateTimeField(default=datetime.now, blank=True) user = models.ForeignKey(User, on_delete=models.CASCADE) # 改为外键关联User,级联删除
修改完成后依次执行python manage.py makemigrations和python manage.py migrate完成表结构更新。
2. 修正视图逻辑
调整代码执行顺序,给所有get()、filter()调用补全正确的查询条件,删除死代码和冗余操作:
from django.shortcuts import render, redirect from django.http import HttpResponse, JsonResponse from .models import User, Message def message(request): username = request.GET.get('username') # 用get_or_create简化查询创建逻辑:存在则取出,不存在则新建 user, _ = User.objects.get_or_create(username=username) # 响应逻辑放到所有业务逻辑最后,保证代码可执行 return render(request, 'member/message.html', { 'username': username, 'user': user }) def send(request): # 加请求方法校验,避免GET请求直接访问报错 if request.method == 'POST': message_content = request.POST['message'] username = request.POST['username'] # 用唯一字段username查询对应用户,不会返回多条结果 send_user = User.objects.get(username=username) Message.objects.create(value=message_content, user=send_user) return HttpResponse('Message sent successfully') def getMessages(request, user): # 从路径参数取用户名,查询唯一对应用户 current_user = User.objects.get(username=user) # 仅过滤当前用户的消息,不返回全量数据 user_messages = Message.objects.filter(user=current_user) return JsonResponse({"messages": list(user_messages.values())})
额外说明
所有用get()查询的场景,必须用带唯一约束的字段(比如主键、加了unique的username)作为查询条件,才能保证只返回1条结果,从根源避免MultipleObjectsReturned异常。视图函数中return语句之后的代码永远不会执行,写业务逻辑时要注意执行顺序。
内容的提问来源于stack exchange,提问作者Dipankar
相关产品推荐
相关产品推荐

