Javier Cárdenas
Javier Cárdenas

Reputation: 4045

Django Form - Select a valid choice. That choice is not one of the available choices

I have a formset (InvoiceItemForm) where the initial form is created by Django, but for adding aditional forms to the formset I use Jquery.

Inside this forms there is a select field (product). The first form of the select is generated by ModelChoiceField, but the rest are generated and populated dynamically using ajax.

When I get the request, the first one (generated by django) does not have problems, but the rest show this form.error in the product field: Select a valid choice. That choice is not one of the available choices.

What I am doing wrong? I checked the forms and I don't see differences between the generated by ModelChoiceField and the ones with Jquery

Model

class Invoice(models.Model):
    number = models.CharField(max_length=200)

    def __str__(self):
        return self.number

class Product(models.Model):
    description = models.CharField(max_length=200)
    measurement_unit = models.CharField(max_length=200)

    def __str__(self):
        return self.description

class InvoiceItem(models.Model):
    invoice = models.ForeignKey(Invoice, related_name='items')
    product = models.ForeignKey(Product)
    unit_price = models.DecimalField(max_digits=8, decimal_places=2, default=0)
    quantity = models.DecimalField(max_digits=8, decimal_places=2, default=0)

Forms.py

class InvoiceItemForm(forms.Form):
    product = forms.ModelChoiceField(queryset=Product.objects.all().order_by('description'))
    unit_price = forms.DecimalField(max_digits=8, decimal_places=2,
                    widget=forms.TextInput(attrs={'placeholder': 'Precio', 'class': 'rate'}))
    quantity = forms.DecimalField(max_digits=8, decimal_places=2,
                widget=forms.TextInput(attrs={'placeholder': 'Cantidad', 'class':'quantity'}))


class InvoiceForm(forms.Form):
    number = forms.CharField()                

Views.py

def invoice(request):
    InvoiceFormSet = formset_factory(InvoiceItemForm)
    if request.method == 'POST':
        invoice_form = InvoiceForm(request.POST)
        formset = InvoiceFormSet(request.POST)
        if invoice_form.is_valid():
            # print("invoice number: ", invoice_form.cleaned_data['number'])            
            number = invoice_form.cleaned_data['number']
            invoice = Invoice(number=number)       
            for form in formset:
                print(form.errors)

Ajax for populating Select Field

$.ajax({
  url: '/ajax/get_products/',
  type: 'GET',
  data:  {},
  dataType: 'json',
  success: function(data){
    let selectItem = $(`#id_form-${total_forms-1}-product`)
    selectItem.append(new Option("---------", "", false, false))
    for (let i=0; i < data['products'].length; i++){
      let p = data['products'][i][0] //product name
      selectItem.append(new Option(p, p, false, false))
    }
    $('select').material_select()
  }
  })

Upvotes: 1

Views: 1764

Answers (1)

Le Minaw
Le Minaw

Reputation: 885

This is due to the way Django validates forms.

To put it simply, it does not expect to be answered a choice that it did not generate.

In the docs : https://docs.djangoproject.com/en/1.11/ref/forms/fields/#choicefield

Validates that the given value exists in the list of choices.

A simple "Django ajax choice form" search on this site will return you some possible workarounds.

Upvotes: 2

Related Questions