2

I ve a weird issue with a MultipleChoiceField that does not return the items that are in the POST QueryDict

here is the Form

class TranslationLanguagesForm(forms.Form):
    languages = forms.MultipleChoiceField(
        widget=forms.SelectMultiple(attrs={"novalidate": "",}),
        choices=languages,
        required=False,
    )

the View is something like (shortened):

class AjaxSpotlerCreateView(View):
    def post(self,request):
        # ...
        # some code before
        #
        translation_form = TranslationLanguagesForm(
            self.request.POST, prefix="translation"
            )
        if translation_form.is_valid():
            translation_languages = translation_form.cleaned_data.get(
                "languages"
                )
        #
        # some code after
        #        

I won't write the whole template but the html created by the form fits what I expected:

<select name="translation-languages" novalidate="" class="form-control " id="id_translation-languages" multiple=""> 
<option value="fr">french</option> 
<option value="en">english</option> <option value="es">spanish</option> </select>

The jquery that sends the data trough ajax request is given below:

function ajaxPOST() {
  var dismiss = false;
  $.ajax({
    method: "POST",
    url: ajaxURL,
    data: getFormData(),
    beforeSend: function () {},
    success: function (data) {
      $target.find(".modal-content").html(data);
      if (data.length == 0) dismiss = true;
    },
    complete: function () {
      if (dismiss) hideUploadModal();
      else showUploadModal();
    }, //complete
  }); //ajax
}

function getFormData() {
  const result = {};
  const $form = $target.find("form#video-loader-form");
  const $inputs = $form.find("input, select, textarea");
  $inputs.each((_, element) => {
    const $element = $(element);
    const type = $element.attr("type");
    const name = $element.attr("name");
    if (name && type == "checkbox" && $element.prop("checked"))
      result[name] = $element.prop("checked");
    else if (name && type != "checkbox") result[name] = $element.val();
  });
  return result;
}

the issue is that the form is never "filled" by the data of request.POST and translation_languages receives always an empty list.

...but self.request.POST.getlist("translation-languages[]") returns the correct values

It only happened on MultipleChoiceField whereas ChoiceField returns the correct value

here are the POST data (you see more data than needed by the form with the issue because there are 4 forms and 1 formset in the view) :

<QueryDict: {'csrfmiddlewaretoken': ['bQQzHTR4JDFZFnmO1ExlPZhqURHswXTmXA9RGC2c05pBM63ns2gnVwUnbnwGzor1'], 'transcription-language': ['en-us'], 'translation-languages[]': ['fr', 'es'], 'spotlers-TOTAL_FORMS': ['1'], 'spotlers-INITIAL_FORMS': ['1'], 'spotlers-MIN_NUM_FORMS': ['0'], 'spotlers-MAX_NUM_FORMS': ['1000'], 'spotlers-0-url': ['https://test-dev-s.storage.googleapis.com/uploads/FR/5e24512/2021/1/9fccac26/9fc37a26-2545-434f-8bd2-0afc3df839aa_full.mp4?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=storage%40funky-tower-264412.iam.gserviceaccount.com%2F20210108%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20210108T125533Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&x-goog-signature=8e737cbc384fab5e11002cbc5e6308'], 'spotlers-0-id': ['9fc37a26-1893-434f-8bd2-0afc3df839ef'], 'spotlers-0-name': ['ultraclimb'], 'spotlers-0-duration': ['00:02:43'], 'spotlers-0-is_postedited': ['true'], 'keywords-keywords': [''], 'glossary-glossary': ['']}>

It seems also that the dict returned by ajax POST creates a weird name for multiselect. The name of the field is postfixed by array symbols : []... So I got 'translation-languages[]': ['fr', 'es'] instead of having 'translation-languages': ['fr', 'es']

David
  • 492
  • 8
  • 17

2 Answers2

0

well finally I got it !

the problem was in the way I have built the POST data in the jquery. I created a dict by collecting all inputs fields names and values but it returned a querydict with a wrong field name for array by postfix it with brackets.

I should rather use $form.serialize() I've made that change and it's now working as expected

David
  • 492
  • 8
  • 17
0

A bit late, but you can set the traditional parameter to true to the ajax call. This way, jQuery will use jQuery.param(yourObject, true) instead of simply jQuery.param(yourObject).

You keys referring to list of values will not be altered.

https://api.jquery.com/jQuery.param/
https://api.jquery.com/jquery.ajax/ (see at the data settings explanation)

Cheers,