I'm using a FormSet that contains several forms that each have a quantity field which is defined like this:
quantity = TypedChoiceField(coerce=int, required=False)
I want to know whether at least one quantity > 0, so in my formset's clean, i write this:
def clean(self):
if sum([form.cleaned_data['quantity'] for form in self.forms]) == 0:
raise forms.ValidationError(_('No products selected'))
So, normally this just works, and form.cleaned_data['quantity'] is an int (as set by coerce=int). But every once in a while (like once every 2000 requests for this form), i get an exception which tells me:
TypeError: unsupported operand type(s) for +: 'int' and 'str'
On that line, which means the form.cleaned_data['quantity'] is a string, and sum() doesn't like summing strings, so it throws an exception. You can test this yourself by starting the python console and typing:
>>> sum([u'1', u'2'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'unicode'
>>>
So my question is, why does this happen? And also why does this happen so rarely? The django documentation tells me the coercing of the TypedChoiceField is guaranteed to be done before clean() is called, so this should not happen.
The bug is hard to fix because it's so hard to reproduce, so i hope one of you guys has had a problem similar to this.
This is on python 2.6 and django 1.3.1.
Thanks in advance!
EDIT So here is the stacktrace:
File "****/handlers/products.py" in process
429. if formset.is_valid():
File "/usr/local/lib/python2.6/dist-packages/django/forms/formsets.py" in is_valid
263. err = self.errors
File "/usr/local/lib/python2.6/dist-packages/django/forms/formsets.py" in _get_errors
241. self.full_clean()
File "/usr/local/lib/python2.6/dist-packages/django/forms/formsets.py" in full_clean
287. self.clean()
File "****/handlers/products.py" in clean
217. if sum([form.cleaned_data['quantity'] for form in self.forms]) == 0:
Exception Type: TypeError at /****/url
Exception Value: unsupported operand type(s) for +: 'int' and 'str'
The default empty_value
for a TypedChoiceField
is the empty string, according to the docs, and that value is not coerced.
I think it's very likely that you're getting an empty value on occasion, and the string that's throwing your TypeError is the empty string. Try:
quantity = TypedChoiceField(coerce=int, required=False, empty_value=0)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With