在调用 save() 之前根据 max_digits 和 decimal_places 属性自动舍入 Django 的 DecimalField

ald*_*ido 8 python django

在 ModelForm 中调用 save() 函数之前,我想根据 max_digits 和 decimal_places 属性自动舍入 Django 的 DecimalField。

目前使用以下:

  • Django 1.8
  • 蟒蛇 2.7

到目前为止我尝试过的。

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


模型.py

amount = models.DecimalField(max_digits = 19, decimal_places = 2)
Run Code Online (Sandbox Code Playgroud)

视图.py

PS会在不同的领域和不同的模型中应用它

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)
Run Code Online (Sandbox Code Playgroud)

表格.py

我计划清理 clean() 函数中的字段并对所有小数字段进行四舍五入,但是当我尝试打印 raw_data 时,没有“金额字段”。

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'}
Run Code Online (Sandbox Code Playgroud)

Vin*_*n-G 6

您主要是收到错误,因为forms.DecimalField有单独的验证器models.DecimalField

data = {'amount': 1.12345 }

class NormalForm(forms.Form):
    amount = forms.DecimalField(max_digits = 19, decimal_places = 2)

normal_form = NormalForm(data)
normal_form.is_valid()  # returns False
normal_form.cleaned_data  # returns {}
Run Code Online (Sandbox Code Playgroud)

并且forms.DecimalField默认用于具有 class 字段的模型的表单models.DecimalField。你可以这样做:

from django import forms
from django.db import models
from decimal import Decimal

def round_decimal(value, places):
    if value is not None:
        # see https://docs.python.org/2/library/decimal.html#decimal.Decimal.quantize for options
        return value.quantize(Decimal(10) ** -places)
    return value

class RoundingDecimalFormField(forms.DecimalField):
    def to_python(self, value):
        value = super(RoundingDecimalFormField, self).to_python(value)
        return round_decimal(value, self.decimal_places)

class RoundingDecimalModelField(models.DecimalField):
    def to_python(self, value):
        # you could actually skip implementing this
        value = super(RoundingDecimalModelField, self).to_python(value)
        return round_decimal(value, self.decimal_places)

    def formfield(self, **kwargs):
        defaults = { 'form_class': RoundingDecimalFormField }
        defaults.update(kwargs)
        return super(RoundingDecimalModelField, self).formfield(**kwargs)
Run Code Online (Sandbox Code Playgroud)

现在,在您使用的任何地方models.DecimalField,请RoundingDecimalModelField改用。您与这些模型一起使用的任何表单现在也将使用自定义表单字段。

class RoundingForm(forms.Form):
    amount = RoundingDecimalFormField(max_digits = 19, decimal_places = 2)

data = {'amount': 1.12345 }

rounding_form = RoundingForm(data)
rounding_form.is_valid()  # returns True
rounding_form.cleaned_data  # returns {'amount': Decimal('1.12')}
Run Code Online (Sandbox Code Playgroud)