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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 05:18:25