Django表单条件判断异常:所有选项均返回同一推荐结果
问题:Django测验程序始终返回第一个推荐结果
我正在学习Django,开发一个根据用户兴趣推荐编程语言的简易测验程序:
- 包含3个是/否问题;
- 表单提交后通过if条件判断生成对应推荐。
预期示例:
- 选是、是、是时,推荐"Javascript, HTML/CSS, React JS, Angular, Figma";
- 选是、是、否时,推荐"HTML/CSS, Javascript, Flutter"。
但实际问题:无论选择哪种组合,程序始终返回第一个推荐结果。
补充排查:通过Answer.objects.all()能看到数据库中有True值,但在前端打印webdev、mobdev、uiux的类型时,始终显示False,同时疑惑若值全为False,为何不返回else分支的结果。
代码细节
models.py
from django.db import models # Create your models here. class User(models.Model): name = models.CharField(max_length=20) def __str__(self): return f"{self.name}" class Answer(models.Model): name = models.ForeignKey(User, on_delete=models.CASCADE) webdev = models.BooleanField(default=True) mobdev = models.BooleanField(default=True) uiux = models.BooleanField(default=True) def __str__(self): return f"{self.name.name}, {self.webdev}, {self.mobdev}, {self.uiux}" class Result(models.Model): name = models.ForeignKey(User, on_delete=models.CASCADE) response = models.CharField(max_length=50, default='Unidentified') def __str__(self): return f"{self.name.name} {self.response}"
forms.py
from django import forms class Quizzes(forms.Form): CHOICES = [ (True, 'Tertarik'), (False, 'Tidak Tertarik') ] name = forms.CharField(label='Siapakah nama anda?', max_length=20) wd = forms.ChoiceField( widget = forms.RadioSelect, choices = CHOICES, label = "Apakah anda tertarik dengan Web Development?" ) md = forms.ChoiceField( widget = forms.RadioSelect, choices = CHOICES, label = "Apakah anda tertarik dengan Mobile Development?" ) ix = forms.ChoiceField( widget = forms.RadioSelect, choices = CHOICES, label = "Apakah anda tertarik dengan UI / UX?" )
views.py
from django.shortcuts import render from django.http import HttpResponse, HttpResponseRedirect from . forms import * from . models import * # Create your views here. def home(response): if response.method == 'POST': form = Quizzes(response.POST) if form.is_valid(): name = form.cleaned_data['name'] wd = form.cleaned_data['wd'] md = form.cleaned_data['md'] ix = form.cleaned_data['ix'] q = User.objects.create(name=name) q.save() q.answer_set.create(webdev=wd, mobdev=md, uiux=ix) if wd and md and ix: q.result_set.create(response='Javascript, HTML/CSS, React JS, Angular, Figma') elif wd and not md and not ix: q.result_set.create(response='Javascript, HTML/CSS, PHP') elif not wd and md and not ix: q.result_set.create(response='Java, Kotlin, Flutter, Swift') elif not wd and not md and ix: q.result_set.create(response='Canva, Figma, Adobe') elif not wd and md and ix: q.result_set.create(response='Swift, Kotlin, Flutter, Java') elif wd and not md and ix: q.result_set.create(response='HTML/CSS, Javascript, Canva, React, Figma') elif wd and md and not ix: q.result_set.create(response='HTML/CSS, Javascript, Flutter') else: q.result_set.create(response='None of our recommendations match your interest') return HttpResponseRedirect(f"/{q.id}") else: form = Quizzes() return render(response, 'home.html', {'form' : form}) def result(response, id): u = User.objects.get(id=id) a = u.answer_set.all() r = u.result_set.all() return render(response, 'result.html', {'u' : u, 'r' : r, 'a' : a})
result.html
{% extends 'base.html' %} {% block result %} {{ u.name }} <br> {{ a }} <br> {{ u.result_set.all }} {% endblock %}
问题根源
问题出在表单的ChoiceField处理逻辑:Django的ChoiceField默认会将选中值转换为字符串类型,而非布尔值。你在CHOICES中定义的(True, 'Tertarik'),提交后form.cleaned_data['wd']拿到的是字符串'True'或'False',不是原生布尔值True/False。
在Python中,任何非空字符串都会被判定为True,所以wd and md and ix永远为真,导致程序始终触发第一个判断分支。
修复方案
方案1:改用BooleanField搭配单选组件
修改forms.py,将三个问题字段替换为BooleanField,并绑定单选框:
from django import forms class Quizzes(forms.Form): name = forms.CharField(label='Siapakah nama anda?', max_length=20) wd = forms.BooleanField( widget=forms.RadioSelect(choices=[(True, 'Tertarik'), (False, 'Tidak Tertarik')]), label="Apakah anda tertarik dengan Web Development?", required=True ) md = forms.BooleanField( widget=forms.RadioSelect(choices=[(True, 'Tertarik'), (False, 'Tidak Tertarik')]), label="Apakah anda tertarik dengan Mobile Development?", required=True ) ix = forms.BooleanField( widget=forms.RadioSelect(choices=[(True, 'Tertarik'), (False, 'Tidak Tertarik')]), label="Apakah anda tertarik dengan UI / UX?", required=True )
方案2:手动转换字符串为布尔值
如果坚持使用ChoiceField,在views.py中对清洗后的数据做类型转换:
# 在form.is_valid()代码块内修改 wd = form.cleaned_data['wd'] == 'True' md = form.cleaned_data['md'] == 'True' ix = form.cleaned_data['ix'] == 'True'
额外优化建议
- 模型中的
Answer和Result可以合并,减少数据冗余; User.objects.create()会自动保存对象,无需额外调用q.save();- 优化结果页面展示,避免直接打印QuerySet:
{% extends 'base.html' %} {% block result %} <h3>Hasil untuk {{ u.name }}</h3> <p>Pilihan Anda:</p> {% for answer in a %} <ul> <li>Web Development: {{ answer.webdev|yesno:"Tertarik,Tidak Tertarik" }}</li> <li>Mobile Development: {{ answer.mobdev|yesno:"Tertarik,Tidak Tertarik" }}</li> <li>UI/UX: {{ answer.uiux|yesno:"Tertarik,Tidak Tertarik" }}</li> </ul> {% endfor %} <p>Rekomendasi:</p> {% for result in r %} <p>{{ result.response }}</p> {% endfor %} {% endblock %}
内容的提问来源于stack exchange,提问作者isca_
相关产品推荐
相关产品推荐

