Automatically round Django's DecimalField according to the max_digits and decimal_places attributes before calling save()
Question: I want to automatically round Django's DecimalField according to the
max_digits and decimal_places attributes before calling save() function in
ModelForm.

currently using the following:

  * django 1.8
  * python 2.7

What I have tried so far.

<https://djangosnippets.org/snippets/10554/>

* * *

**models.py**

    
    
    amount = models.DecimalField(max_digits = 19, decimal_places = 2)
    

**views.py**

P.S. gonna apply it in different fields and in different models

    
    
    data = {"amount" : 100.1234,"name":"John Doe",...}
    form = My_form(data)
    if form.is_valid(): //the error throws from here.
        form.save()
    else:
        raise ValueError(form.errors)
    

**forms.py**

I plan to clean the fields in clean() function and do the rounding off of all
decimal fields but when I try to print the raw_data, there's no 'amount field'
anymore.

    
    
    class My_form(forms.ModelForm):
        Class Meta:
            model = My_model
            fields = ('amount','name')
    def clean(self):
        raw_data = self.cleaned_data
        print(raw_data) //only prints {'name' : 'John Doe'}
    


Answer: If you are assigning directly to a model instance, you don't need to worry
about it. The field object will quantize the value (rounding it) to the
decimal point level you set in your model definition.

If you are dealing with a `ModelForm`, the default `DecimalField` will require
that any input match the model field's decimal points. The easiest way to
handle this in general is probably to subclass the model `DecimalField`,
removing the decimal-specific validator and relying on the underlying
conversion to quantize the data, with something like this:

    
    
    from django.db.models.fields import DecimalField
    
    class RoundingDecimalField(DecimalField):
    
        @cached_property
        def validators(self):
            return super(DecimalField, self).validators
    
        def formfield(self, **kwargs):
            defaults = {
                'max_digits': self.max_digits,
                'decimal_places': 4, # or whatever number of decimal places you want your form to accept, make it a param if you like
                'form_class': forms.DecimalField,
            }
            defaults.update(kwargs)
            return super(RoundingDecimalField, self).formfield(**defaults)
    

Then in your models:

    
    
    amount = RoundingDecimalField(max_digits = 19, decimal_places = 2)
    

(Don't actually put the field class in the same field as the model, that's
just for example.)

This is probably less correct in absolute terms than defining a custom field
form, which was my first suggestion, but is less work to use.

