Search code examples
djangodjango-formsdjango-templates

Django ModelMultipleChoiceField produces duplicate keys in rls params


I have a form in django with a ModelMultipleChoiceField, but when I submit the data, I have the same parameter repeated in the url for every selected option (like localhost:8000/search/?category=1&category=2).

Here's a toy example:

#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()

In the template:

    <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>

The form is displayed correctly:

enter image description here

But when I click submit I get the following url: http://localhost:8000/search/?start_date=&end_date=&category=1&category=2


Solution

  • Having same keys in query params is the normal behavior.

    You can use getlist function in your view to make it work. Something like this:

    if categories := self.request.GET.getlist("category", []):
        object_list = object_list.filter(
            category__id__in=categories,
        )