Django自定义HTML表单无法单字段筛选数据求助
Django自定义表单后筛选需填全字段的问题
原本使用{{form.as_p}}或{{form|crispy}}自动渲染表单时,单个字段即可正常筛选数据,但自定义HTML表单后,必须填满所有字段才能得到正确结果——即便forms.py中已设置所有字段为非必填,问题根源在自定义的HTML代码里。
相关代码
views.py
def buy_files(request): bdfiles = FeedFile.objects.all() # bdfiles = UploadFile.objects.all() form = FileFilterForm(request.GET) if form.is_valid(): if form.cleaned_data["number_course"]: bdfiles = bdfiles.filter(feed__number_course = form.cleaned_data["number_course"]) if form.cleaned_data["number_semestr"]: bdfiles = bdfiles.filter(feed__number_semestr = form.cleaned_data["number_semestr"]) if form.cleaned_data["subjectt"]: bdfiles = bdfiles.filter(feed__subjectt = form.cleaned_data["subjectt"]) if form.cleaned_data["type_materials"]: bdfiles = bdfiles.filter(feed__type_materials = form.cleaned_data["type_materials"]) if form.cleaned_data["institute"]: bdfiles = bdfiles.filter(feed__institute = form.cleaned_data["institute"]) return render(request, 'chat/files/buyfile.html', {'bdfiles': bdfiles, 'form':form})
HTML代码
<div style="float: right; margin-bottom: 10%; margin-top: 10%;" class="form-group row" data-aos="fade-up"> <form action="" method="get" style="width:90%"> {% csrf_token %} <!-- {{form|crispy}}--> <p><label class="form-label">Курс: </label> {{ form.number_course }}</p> <div class="form-error">{{ form.number_course.errors }}</div> <p><label class="form-label">Семестр: </label> {{ form.number_semestr }}</p> <div class="form-error">{{ form.number_semestr.errors }}</div> <p><label class="form-label">Дисциплина </label> {{ form.subjectt }}</p> <div class="form-error">{{ form.subjectt.errors }}</div> <p><select name = "type_materials" class="form-select" aria-label="Тип материала"> <option selected>Тип материала</option> <option value="Практические работы">Практические работы</option> <option value="Лабораторные работы">Лабораторные работы</option> <option value="Курсовые">Курсовые</option> <option value="Дипломная работа">Дипломная работа</option> <option value="Лекции">Лекции</option> <option value="Диск с работами">Диск с работами</option> <option value="Другое">Другое</option> </select></p> <p><select name = "institute" class="form-select" aria-label="Институт"> <option selected>Институт</option> <option value="ИВТИ">ИВТИ</option> <option value="ГПИ">ГПИ</option> <option value="ИЭЭ">ИЭЭ</option> <option value="ИГВИЭ">ИГВИЭ</option> <option value="ИнЭИ">ИнЭИ</option> <option value="ИРЭ">ИРЭ</option> <option value="ИЭТЭ">ИЭТЭ</option> <option value="ИТАЭ">ИТАЭ</option> <option value="ИЭВТ">ИЭВТ</option> <option value="ЭнМИ">ЭнМИ</option> <option value="Другой">Другой</option> </select></p> <div class="form-error">{{ form.institute.errors }}</div> <button type="submit" class="btn btn-primary">Найти</button> </form> </div>
forms.py
class FileFilterForm(forms.Form): number_course = forms.IntegerField(label='Курс',required=False, widget=forms.NumberInput(attrs={'class': 'form-control'})) number_semestr = forms.IntegerField(label='Семестр',required=False, widget=forms.NumberInput(attrs={'class': 'form-control'})) subjectt = forms.CharField(label='Дисциплина',required=False,widget=forms.TextInput(attrs={'class': 'form-control'})) type_materials = forms.CharField(label='Тип материала',required=False,widget=forms.TextInput(attrs={'class': 'form-control'})) institute = forms.CharField(label='Институт',required=False,widget=forms.TextInput(attrs={'class': 'form-control'}))
问题原因及修复方案
问题根源
手动编写的type_materials和institute下拉框,默认选中的选项未设置value="",而是将显示文本(如"Тип материала")作为提交值。当用户未选择其他选项时,该文本会被传入form.cleaned_data,导致筛选逻辑执行filter操作,但数据库中无匹配该文本的记录,最终返回空结果。
修复方法
方法1:修改HTML下拉框默认选项
给默认选项添加value="",让未选择时提交空值:
<!-- 修改type_materials下拉框 --> <select name="type_materials" class="form-select" aria-label="Тип материала"> <option selected value="">Тип материала</option> <!-- 其余选项保持不变 --> </select> <!-- 修改institute下拉框 --> <select name="institute" class="form-select" aria-label="Институт"> <option selected value="">Институт</option> <!-- 其余选项保持不变 --> </select>
方法2:用Django表单渲染下拉框(更规范)
在forms.py中将type_materials和institute改为ChoiceField并设置选项,再通过表单对象渲染下拉框:
# 修改forms.py class FileFilterForm(forms.Form): # 保留原有字段 number_course = forms.IntegerField(label='Курс',required=False, widget=forms.NumberInput(attrs={'class': 'form-control'})) number_semestr = forms.IntegerField(label='Семестр',required=False, widget=forms.NumberInput(attrs={'class': 'form-control'})) subjectt = forms.CharField(label='Дисциплина',required=False,widget=forms.TextInput(attrs={'class': 'form-control'})) # 新增选项常量 TYPE_MATERIALS_CHOICES = [ ('', 'Тип материала'), ('Практические работы', 'Практические работы'), ('Лабораторные работы', 'Лабораторные работы'), ('Курсовые', 'Курсовые'), ('Дипломная работа', 'Дипломная работа'), ('Лекции', 'Лекции'), ('Диск с работами', 'Диск с работами'), ('Другое', 'Другое'), ] INSTITUTE_CHOICES = [ ('', 'Институт'), ('ИВТИ', 'ИВТИ'), ('ГПИ', 'ГПИ'), ('ИЭЭ', 'ИЭЭ'), ('ИГВИЭ', 'ИГВИЭ'), ('ИнЭИ', 'ИнЭИ'), ('ИРЭ', 'ИРЭ'), ('ИЭТЭ', 'ИЭТЭ'), ('ИТАЭ', 'ИТАЭ'), ('ИЭВТ', 'ИЭВТ'), ('ЭнМИ', 'ЭнМИ'), ('Другой', 'Другой'), ] # 修改为ChoiceField type_materials = forms.ChoiceField(label='Тип материала', required=False, choices=TYPE_MATERIALS_CHOICES, widget=forms.Select(attrs={'class': 'form-select'})) institute = forms.ChoiceField(label='Институт', required=False, choices=INSTITUTE_CHOICES, widget=forms.Select(attrs={'class': 'form-select'}))
然后在HTML中替换为表单渲染的下拉框:
<p><label class="form-label">Тип материала </label> {{ form.type_materials }}</p> <div class="form-error">{{ form.type_materials.errors }}</div> <p><label class="form-label">Институт </label> {{ form.institute }}</p> <div class="form-error">{{ form.institute.errors }}</div>
两种方法都能实现未选择时提交空值,让筛选逻辑跳过对应字段的过滤,恢复单个字段筛选的功能。
内容的提问来源于stack exchange,提问作者Xrystik
相关产品推荐
相关产品推荐

