Skip to content

Commit 6338ce8

Browse files
kiyoqokotomchristie
authored andcommitted
Add localize keyword argument to DecimalField (#4233)
Add `localize` keyword argument for DecimalField
1 parent b10de37 commit 6338ce8

File tree

3 files changed

+34
-2
lines changed

3 files changed

+34
-2
lines changed

docs/api-guide/fields.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,10 @@ Corresponds to `django.db.models.fields.DecimalField`.
261261

262262
- `max_digits` The maximum number of digits allowed in the number. Note that this number must be greater than or equal to decimal_places.
263263
- `decimal_places` The number of decimal places to store with the number.
264-
- `coerce_to_string` Set to `True` if string values should be returned for the representation, or `False` if `Decimal` objects should be returned. Defaults to the same value as the `COERCE_DECIMAL_TO_STRING` settings key, which will be `True` unless overridden. If `Decimal` objects are returned by the serializer, then the final output format will be determined by the renderer.
264+
- `coerce_to_string` Set to `True` if string values should be returned for the representation, or `False` if `Decimal` objects should be returned. Defaults to the same value as the `COERCE_DECIMAL_TO_STRING` settings key, which will be `True` unless overridden. If `Decimal` objects are returned by the serializer, then the final output format will be determined by the renderer. Note that setting `localize` will force the value to `True`.
265265
- `max_value` Validate that the number provided is no greater than this value.
266266
- `min_value` Validate that the number provided is no less than this value.
267+
- `localize` Set to `True` to enable localization of input and output based on the current locale. This will also force `coerce_to_string` to `True`. Defaults to `False`. Note that data formatting is enabled if you have set `USE_L10N=True` in your settings file.
267268

268269
#### Example usage
269270

rest_framework/fields.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
)
2626
from django.utils.duration import duration_string
2727
from django.utils.encoding import is_protected_type, smart_text
28+
from django.utils.formats import localize_input, sanitize_separators
2829
from django.utils.functional import cached_property
2930
from django.utils.ipv6 import clean_ipv6_address
3031
from django.utils.translation import ugettext_lazy as _
@@ -871,6 +872,7 @@ def __init__(self, **kwargs):
871872
self.validators.append(MinValueValidator(self.min_value, message=message))
872873

873874
def to_internal_value(self, data):
875+
874876
if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH:
875877
self.fail('max_string_length')
876878

@@ -895,11 +897,15 @@ class DecimalField(Field):
895897
}
896898
MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs.
897899

898-
def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None, **kwargs):
900+
def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None,
901+
localize=False, **kwargs):
899902
self.max_digits = max_digits
900903
self.decimal_places = decimal_places
904+
self.localize = localize
901905
if coerce_to_string is not None:
902906
self.coerce_to_string = coerce_to_string
907+
if self.localize:
908+
self.coerce_to_string = True
903909

904910
self.max_value = max_value
905911
self.min_value = min_value
@@ -923,7 +929,12 @@ def to_internal_value(self, data):
923929
Validate that the input is a decimal number and return a Decimal
924930
instance.
925931
"""
932+
926933
data = smart_text(data).strip()
934+
935+
if self.localize:
936+
data = sanitize_separators(data)
937+
927938
if len(data) > self.MAX_STRING_LENGTH:
928939
self.fail('max_string_length')
929940

@@ -988,6 +999,9 @@ def to_representation(self, value):
988999

9891000
if not coerce_to_string:
9901001
return quantized
1002+
if self.localize:
1003+
return localize_input(quantized)
1004+
9911005
return '{0:f}'.format(quantized)
9921006

9931007
def quantize(self, value):

tests/test_fields.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import pytest
77
from django.http import QueryDict
8+
from django.test import TestCase, override_settings
89
from django.utils import six, timezone
910

1011
import rest_framework
@@ -894,6 +895,22 @@ class TestNoStringCoercionDecimalField(FieldValues):
894895
)
895896

896897

898+
class TestLocalizedDecimalField(TestCase):
899+
@override_settings(USE_L10N=True, LANGUAGE_CODE='pl')
900+
def test_to_internal_value(self):
901+
field = serializers.DecimalField(max_digits=2, decimal_places=1, localize=True)
902+
self.assertEqual(field.to_internal_value('1,1'), Decimal('1.1'))
903+
904+
@override_settings(USE_L10N=True, LANGUAGE_CODE='pl')
905+
def test_to_representation(self):
906+
field = serializers.DecimalField(max_digits=2, decimal_places=1, localize=True)
907+
self.assertEqual(field.to_representation(Decimal('1.1')), '1,1')
908+
909+
def test_localize_forces_coerce_to_string(self):
910+
field = serializers.DecimalField(max_digits=2, decimal_places=1, coerce_to_string=False, localize=True)
911+
self.assertTrue(isinstance(field.to_representation(Decimal('1.1')), six.string_types))
912+
913+
897914
class TestNoDecimalPlaces(FieldValues):
898915
valid_inputs = {
899916
'0.12345': Decimal('0.12345'),

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy