Opened 9 years ago
Last modified 4 years ago
#26459 new New feature
Allow providing DecimalField with a custom context
Reported by: | yasondinalt | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.9 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
DecimalField has weird behavior in case of float values passed to field.
If decimal_places = 1
float 2.15 will be saved as 2.1 (!)
float 2.25 will be saved as 2.2 (!)
But if float value first converted to str:
float 2.15 will be saved as 0.2 (ok)
float 2.25 will be saved as 0.2 (!)
It's because of default decimal rounding ROUND_HALF_EVEN.
As I understand build-in round() use rounding similar to ROUND_HALF_UP.
I tried first cast float to str, then use ROUND_HALF_UP, so now:
float 2.15 will be saved as 0.2 (ok)
float 2.25 will be saved as 0.3 (ok)
Attachments (2)
Change History (9)
comment:1 by , 9 years ago
Needs tests: | set |
---|
by , 9 years ago
Attachment: | 0001-tests-format-float-to-Decimal-with-proper-rounding.patch added |
---|
follow-up: 3 comment:2 by , 9 years ago
Could you give a snippet of the application code where you run into this issue?
comment:3 by , 9 years ago
Replying to timgraham:
Could you give a snippet of the application code where you run into this issue?
class Invoice(models.Model): # same as django-paypal use mc_gross = models.DecimalField(max_digits=64, decimal_places=2, default=0) invoice.mc_gross = 2.215 # float invoice.save()
In DB will be value 2.21 (or if 2.225 -> 2.22)
by , 9 years ago
Attachment: | 0001-DecimalField-rounding-first-cast-to-str-then-use-ROU.patch added |
---|
Changes
comment:4 by , 9 years ago
Needs tests: | unset |
---|
I'm not sure whether or not to accept the ticket so I asked for advice on the django-developers mailing list.
p.s. You don't need to attach patches on the ticket when you also send a pull request.
comment:5 by , 9 years ago
Has patch: | unset |
---|---|
Summary: | DecimalField float rounding → Allow providing DecimalField with a custom context |
Triage Stage: | Unreviewed → Accepted |
Type: | Bug → New feature |
Accepting per Aymeric's proposal on the mailing list:
Currently DecimalField
accepts max_digits
and decimal_places
options. I think it should accept a decimal context and delegate all operations to that context.
I suggest the following behavior:
- start with the decimal context provided in a kwarg to
DecimalField
or, if there is None, the current context returned bygetcontext()
. - modify that context to take into account
max_digits
anddecimal_places
- ask the context to perform whatever operations we need
Tests