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

Django中ModelMultipleChoiceField提交后URL出现重复参数问题

Django中ModelMultipleChoiceField提交后URL参数重复的问题

我在Django中创建了包含ModelMultipleChoiceField的表单,提交数据时URL中每个选中的选项都会重复同一个参数,例如localhost:8000/search/?category=1&category=2。

示例代码

forms.py

class SearchForm(forms.ModelForm):
    category = forms.ModelMultipleChoiceField(Category.objects.all(), required=False)
    
    class Meta:
        model = Document
        fields = ("start_date", "end_date", "category")

views.py

class SearchResultsView(ListView, FormView):
    model = Document
    template_name = "archive/document_list.html"
    context_object_name = "documents"
    form_class = SearchForm

    def get_queryset(self):
        object_list = Document.objects.all()
        
        if start_date := self.request.GET.get("start_date"):
            object_list = object_list.filter(date__gte=start_date)
        if end_date := self.request.GET.get("end_date"):
            object_list = object_list.filter(date__lte=end_date)
        if category := self.request.GET.get("category"):
            object_list = object_list.filter(
                category__name=category,
            )
        return object_list.distinct()

模板代码

<form action="{% url 'search_results' %}" method="get">
  <div class="flexline flex-wrap justify-content">
    {{ form|materializecss }}
  <div>
    <button class="btn" type="submit">Submit</button>
  </div>
</form>

提交后得到的URL示例:
http://localhost:8000/search/?start_date=&end_date=&category=1&category=2


问题分析

URL中出现多个相同参数是HTTP GET请求提交多选字段的标准行为,但当前视图中使用request.GET.get("category")只能获取最后一个选中的分类值,会导致筛选逻辑无法正确匹配所有选中的分类,这才是需要解决的核心问题。

解决方案

1. 修复视图筛选逻辑(推荐)

将获取分类参数的方式从get()改为getlist(),它会返回所有选中的分类ID列表,再配合__in查询实现多分类筛选:

修改views.py中的get_queryset方法:

def get_queryset(self):
    object_list = Document.objects.all()
    
    if start_date := self.request.GET.get("start_date"):
        object_list = object_list.filter(date__gte=start_date)
    if end_date := self.request.GET.get("end_date"):
        object_list = object_list.filter(date__lte=end_date)
    # 处理多选分类
    if categories := self.request.GET.getlist("category"):
        object_list = object_list.filter(
            category__id__in=categories,
        )
    return object_list.distinct()

注意:ModelMultipleChoiceField默认提交的是模型主键ID,因此用category__id__in筛选更高效;如果需要按分类名称筛选,需先将ID转换为对应名称,但不推荐这种绕路方式。

2. (可选)自定义URL参数格式(非必需)

如果觉得多个重复参数的URL不美观,可以通过前端JS将多选值拼接为逗号分隔的字符串,作为单个参数提交。但这种方式不符合HTTP标准规范,仅在有特殊需求时使用:

修改模板添加JS处理

<form action="{% url 'search_results' %}" method="get" id="search-form">
  <div class="flexline flex-wrap justify-content">
    {{ form|materializecss }}
  <div>
    <button class="btn" type="submit">Submit</button>
  </div>
</form>

<script>
document.getElementById('search-form').addEventListener('submit', function(e) {
  e.preventDefault();
  const formData = new FormData(this);
  const categories = formData.getAll('category');
  formData.delete('category');
  if (categories.length > 0) {
    formData.append('category', categories.join(','));
  }
  const params = new URLSearchParams(formData);
  window.location.href = `${this.action}?${params.toString()}`;
});
</script>

同步修改视图逻辑

def get_queryset(self):
    object_list = Document.objects.all()
    
    if start_date := self.request.GET.get("start_date"):
        object_list = object_list.filter(date__gte=start_date)
    if end_date := self.request.GET.get("end_date"):
        object_list = object_list.filter(date__lte=end_date)
    if category := self.request.GET.get("category"):
        categories = category.split(',')
        object_list = object_list.filter(
            category__id__in=categories,
        )
    return object_list.distinct()

内容的提问来源于stack exchange,提问作者danilociaffi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 14:53:11