Ben
Ben

Reputation: 16600

Django--Form validation (Why can't I manually clean an Integer Form Field)

This should be pretty straightforward but I'm not figuring it out from the Django documentation. I have an IntegerField Model Field from which I've created a ModelForm Field. The field in question contains $ values (price) and it would be preferable from a UX standpoint if the user did not receive a error message ('enter whole number') when they input $10 instead of 10.

I've tried manual form cleaning but it seems that the clean_field method is run after other validation methods. My reading so far seems to confirm that as well.

    def clean_bill(self):
          bill = self.cleaned_data["bill"]
          if '$' in bill:
              bill=bill.replace('$','',1)   
          return bill

Is there a way around this while maintaining the IntegerField in the modelform? Should I just make it a RegexField?

EDIT: I ended up going with a combination of the above and a RegexField. Still curious if there is another/better way.

        bill= forms.RegexField(label=_("Bill"), max_length=10,required=True, regex=r'^\$?[\d]+$',
    error_messages = {'invalid': _("Please enter a whole number.")})

Upvotes: 3

Views: 2608

Answers (2)

John Mee
John Mee

Reputation: 52243

Create an IntegerField in the model, and a CharField in the form.

You can still use modelform to do this but you'll have to:

  1. 'exclude' the model field from the form,
  2. write a clean_bill method in the form
  3. set the value of the model's field to the parsed integer value

try this and/or this

Upvotes: 4

Torsten Engelbrecht
Torsten Engelbrecht

Reputation: 13486

Yes, you are right. According to the Django docs of form and field validation it will not even go to your clean method and already raise ValidationError in the first step (to_python method). There is nothing much you can do on the form level I think. What you could do though is processing the POST data in the view before passing it to the form. Some simple example:

post_dict = request.POST.copy()   #makes a copy of request.POST so you can modify it
bill = post_dict['bill']
if '$' in bill:
    bill = bill.replace('$','',1)   
post_dict['bill'] = bill
# pass post_dict to your form instead of request.POST
...

Upvotes: 1

Related Questions