Django生产环境使用PostgreSQL出现quiz.models.Question.DoesNotExist报错
问题根因
- 你的代码逻辑采用前端提交的问题文本作为唯一查询条件匹配Question表记录,该设计存在数据库兼容问题:
- SQLite默认字符串匹配为大小写不敏感,且会自动忽略部分不可见字符差异,所以开发环境运行正常
- PostgreSQL默认字符串匹配为大小写敏感,同时会严格校验所有字符包括空格、换行、富文本HTML标签格式,只要提交文本和数据库存储的text字段有任何细微差异就会查询失败
- 你用的
RichTextUploadingField存储的是带HTML标签的富文本,前端渲染和提交时很容易出现标签格式、空格、换行的细微变化,本身就不适合作为查询条件使用 - 代码中
if Question.objects.all():的判断完全不起容错作用,只要Question表存在任意数据就会进入查询逻辑,无法避免单个key匹配失败的报错
修复方案
长期最优方案(推荐)
1. 修改前端提交逻辑
不要用问题文本作为表单字段的key,改为用Question的主键id作为key,比如前端渲染问题时,每个问题的input/select的name属性设置为question_{{ question.id }},提交到后端的key为问题id而非文本。
2. 调整后端查询逻辑
将原有的文本查询替换为主键id查询,性能和稳定性都远高于文本匹配:
def save_quiz_view(request, pk, book_pk): quiz = Quiz.objects.get(pk=pk) if request.is_ajax() and not request.user.profile in quiz.completed_users.all(): questions = [] data = request.POST data_ = dict(data.lists()) data_.pop('csrfmiddlewaretoken') for _k in data_.keys(): # 提取key中的问题id,如key为question_12则提取数值12 question_id = _k.split('_')[-1] question = Question.objects.get(id=question_id) questions.append(question) # 后续获取用户提交答案的逻辑也对应改为用id作为key取值 # 其余原有逻辑保持不变即可
临时兼容方案
如果暂时无法修改前端代码,可以先将查询改为PostgreSQL支持的大小写不精确匹配,临时解决报错问题:
# 把原代码中的question = Question.objects.get(text=k)替换为 question = Question.objects.get(text__iexact=k)
注意:该方案仅为临时修复,富文本的不可见字符差异仍可能导致查询失败,长期仍建议改用主键id作为查询条件
补充校验
部署后先核对生产环境PostgreSQL的Question表数据是否和开发环境一致,确认数据迁移导入时没有出现富文本转义、格式丢失的问题。
内容的提问来源于stack exchange,提问作者Arthur
相关产品推荐
相关产品推荐

