I am writing a simple form in Django which includes a ChoiceField allowing users to choose from a list of categories. For sure I want to pass the category_id to be processed. This is my code:
models.py:
class Category(models.Model):
category = models.CharField(max_length=128)
def __unicode__(self):
return self.category
class Product(models.Model):
code = models.CharField(max_length=75)
name = models.CharField(max_length=128)
price = models.DecimalField(max_digits=7, decimal_places=2)
category = models.ForeignKey(Category)
def __unicode__(self):
return self.name
forms.py
class AddProductForm(forms.Form):
category = forms.ChoiceField(label=_('Category'))
product = forms.CharField(label=_('Product'), widget=forms.TextInput())
code = forms.CharField(label=_('Code'), widget=forms.TextInput())
price = forms.DecimalField(label=_('Price'))
Now in the views.py I fill in the choices:
def add_product_form(request):
form = AddProductForm()
form.fields['category'].choices =[(c.id, c.category) for c in Category.objects.all()]
return render_to_response('product-form.html', {'form':form})
Now everything seems to be okay except when I submit the form. It complains about the IDs of the Category. It says: Select a valid choice. 1 is not one of the available choices
This is how I am processing the form:
def add_product(request):
if request.method == 'POST':
form = AddProductForm(request.POST)
if form.is_valid():
category = request.cleaned_data['category']
product = form.cleaned_data['product']
code = form.cleaned_data['code']
price = form.cleaned_data['price']
product = Product(code=code, name=product, price=price, category_id=category)
product.save()
return HttpResponseRedirect('/ms-admin/')
else:
form = AddProductForm() # more is required here to fill the choices again
return render_to_response('product-form.html', {'form':form})
I tried the same with TypedChoiceField but got the same invalid data. I know it has to do with the conversion between string and int and the unicode stuff. Can you please explain?
For some reason, you've separated the view that renders the form - including adding the choices - and the view that processes the submission. You don't add the choices on submission, so of course the values are not going to be valid.
You should get rid of the
add_product_form
view altogether. You could move theform.fields['category'].choices...
bit into theadd_product
view, but a better solution is to use the form field that's specifically designed for getting choices from a model or queryset - ieModelChoiceField
.Just use:
in your form definition.