Django model integer field with floating point form input

I am working with a django model that stores currency values ​​as integers. those. GBP 22.35 is received in the form of 2235.

When this model receives the visualization as a form, I need to be able to associate the widget with this whole field, so it can be edited as if it were a floating point value (that is, up to two decimal places - 22.35) and confirmed as such, form .save () then you need to save your own integer value in db.

I tried to create a custom FormField / Widget pair, which includes dividing by 100 in the widget visualization and multiplying backups in the to_python fields, but all this goes wrong if there is an error in the form. The widget saves re-splitting the value.

I understand that this can be avoided by using the float / decimal model fields, but this is not an option in this case.

Is this something that people have done before? Any pointers? Thank.

+4
source share
1 answer

You can implement a subclass DecimalFieldthat processes this conversion overs:

import decimal
from django.db import models
from django.core import exceptions
from django.utils.translation import ugettext_lazy as _

class CentsField(models.IntegerField):
    empty_strings_allowed = False
    default_error_messages = {
        'invalid': _("'%(value)s' value must be a decimal number."),
    }
    description = _("Fixed-point number")

    __metaclass__ = models.SubfieldBase

    def to_python(self, value):
        if value is None or isinstance(value, decimal.Decimal):
            return value
        try:
            if isinstance(value, int):
                return decimal.Decimal(value) / 100
            else:
                return decimal.Decimal(value)
        except decimal.InvalidOperation:
            raise exceptions.ValidationError(
                self.error_messages['invalid'],
                code='invalid',
                params={'value': value},
            )

    def get_prep_value(self, value):
        return int(value * 100)

It should behave as DecimalFieldin your Django-code, but as IntegerFieldin your database.

Update: simpler implementation obtained from IntegerFieldinstead DecimalField; added verification implemented inDecimalField.to_python

0
source

Source: https://habr.com/ru/post/1531168/


All Articles