Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add localize keyword argument to DecimalField #4233

Merged
merged 4 commits into from
Jul 6, 2016
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/api-guide/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ Corresponds to `django.db.models.fields.DecimalField`.
- `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.
- `max_value` Validate that the number provided is no greater than this value.
- `min_value` Validate that the number provided is no less than this value.
- `localize` Set to `True` to enable localization of input and output based on the current locale. Defaults to `False`. Note that data formatting is enabled if you have set `USE_L10N=True` in your settings file.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumable we should also ensure that setting localize forces coerce_to_string to be True, right?


#### Example usage

Expand Down
14 changes: 13 additions & 1 deletion rest_framework/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
)
from django.utils.duration import duration_string
from django.utils.encoding import is_protected_type, smart_text
from django.utils.formats import localize_input, sanitize_separators
from django.utils.functional import cached_property
from django.utils.ipv6 import clean_ipv6_address
from django.utils.translation import ugettext_lazy as _
Expand Down Expand Up @@ -871,6 +872,7 @@ def __init__(self, **kwargs):
self.validators.append(MinValueValidator(self.min_value, message=message))

def to_internal_value(self, data):

if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH:
self.fail('max_string_length')

Expand All @@ -895,9 +897,11 @@ class DecimalField(Field):
}
MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs.

def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None, **kwargs):
def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None,
localize=False, **kwargs):
self.max_digits = max_digits
self.decimal_places = decimal_places
self.localize = localize
if coerce_to_string is not None:
self.coerce_to_string = coerce_to_string

Expand All @@ -923,7 +927,12 @@ def to_internal_value(self, data):
Validate that the input is a decimal number and return a Decimal
instance.
"""

if self.localize:
data = sanitize_separators(data)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would make slightly more sense after the smart_text/.strip() line below.


data = smart_text(data).strip()

if len(data) > self.MAX_STRING_LENGTH:
self.fail('max_string_length')

Expand Down Expand Up @@ -988,6 +997,9 @@ def to_representation(self, value):

if not coerce_to_string:
return quantized
if self.localize:
return localize_input(quantized)

return '{0:f}'.format(quantized)

def quantize(self, value):
Expand Down
13 changes: 13 additions & 0 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import pytest
from django.http import QueryDict
from django.test import TestCase, override_settings
from django.utils import six, timezone

import rest_framework
Expand Down Expand Up @@ -894,6 +895,18 @@ class TestNoStringCoercionDecimalField(FieldValues):
)


class TestLocalizedDecimalField(TestCase):
@override_settings(USE_L10N=True, LANGUAGE_CODE='pl')
def test_to_internal_value(self):
field = serializers.DecimalField(max_digits=2, decimal_places=1, localize=True)
self.assertEqual(field.to_internal_value('1,1'), Decimal('1.1'))

@override_settings(USE_L10N=True, LANGUAGE_CODE='pl')
def test_to_representation(self):
field = serializers.DecimalField(max_digits=2, decimal_places=1, localize=True)
self.assertEqual(field.to_representation(Decimal('1.1')), '1,1')


class TestNoDecimalPlaces(FieldValues):
valid_inputs = {
'0.12345': Decimal('0.12345'),
Expand Down