This commit is contained in:
HoodyH 2025-09-15 20:46:18 +01:00 committed by GitHub
commit fa5414d657
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 117 additions and 3 deletions

View File

@ -269,6 +269,18 @@ Corresponds to `django.db.models.fields.IntegerField`, `django.db.models.fields.
* `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.
## BigIntegerField
An biginteger representation.
Corresponds to `django.db.models.fields.BigIntegerField`.
**Signature**: `BigIntegerField(max_value=None, min_value=None, coerce_to_string=None)`
* `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.
* `coerce_to_string` Set to `True` if string values should be returned for the representation, or `False` if `BigInteger` objects should be returned. Defaults to the same value as the `COERCE_BIGINT_TO_STRING` settings key, which will be `True` unless overridden. If `BigInterger` objects are returned by the serializer, then the final output format will be determined by the renderer.
## FloatField
A floating point representation.

View File

@ -371,6 +371,14 @@ When set to `True`, the serializer `DecimalField` class will return strings inst
Default: `True`
#### COERCE_BIGINT_TO_STRING
When returning biginteger objects in API representations that do not support numbers up to 2^64, it is best to return the value as a string. This avoids the loss of precision that occurs with biginteger implementations.
When set to `True`, the serializer `BigIntegerField` class will return strings instead of `BigInteger` objects. When set to `False`, serializers will return `BigInteger` objects, which the default JSON encoder will return as numbers.
Default: `False`
---
## View names and descriptions

View File

@ -921,6 +921,36 @@ class IntegerField(Field):
return int(value)
class BigIntegerField(IntegerField):
default_error_messages = {
'invalid': _('A valid biginteger is required.'),
'max_value': _('Ensure this value is less than or equal to {max_value}.'),
'min_value': _('Ensure this value is greater than or equal to {min_value}.'),
'max_string_length': _('String value too large.')
}
def __init__(self, coerce_to_string=None, **kwargs):
super().__init__(**kwargs)
if coerce_to_string is not None:
self.coerce_to_string = coerce_to_string
def to_representation(self, value):
coerce_to_string = getattr(self, 'coerce_to_string', api_settings.COERCE_BIGINT_TO_STRING)
if value is None:
if coerce_to_string:
return ''
else:
return None
if coerce_to_string:
return str(value)
else:
return int(value)
class FloatField(Field):
default_error_messages = {
'invalid': _('A valid number is required.'),

View File

@ -56,7 +56,7 @@ from rest_framework.fields import ( # NOQA # isort:skip
BooleanField, CharField, ChoiceField, DateField, DateTimeField, DecimalField,
DictField, DurationField, EmailField, Field, FileField, FilePathField, FloatField,
HiddenField, HStoreField, IPAddressField, ImageField, IntegerField, JSONField,
ListField, ModelField, MultipleChoiceField, ReadOnlyField,
ListField, ModelField, MultipleChoiceField, ReadOnlyField, BigIntegerField,
RegexField, SerializerMethodField, SlugField, TimeField, URLField, UUIDField,
)
from rest_framework.relations import ( # NOQA # isort:skip
@ -906,7 +906,8 @@ class ModelSerializer(Serializer):
"""
serializer_field_mapping = {
models.AutoField: IntegerField,
models.BigIntegerField: IntegerField,
models.BigAutoField: BigIntegerField,
models.BigIntegerField: BigIntegerField,
models.BooleanField: BooleanField,
models.CharField: CharField,
models.CommaSeparatedIntegerField: CharField,

View File

@ -116,6 +116,7 @@ DEFAULTS = {
'COMPACT_JSON': True,
'STRICT_JSON': True,
'COERCE_DECIMAL_TO_STRING': True,
'COERCE_BIGINT_TO_STRING': False,
'UPLOADED_FILES_USE_URL': True,
# Browsable API

View File

@ -1099,6 +1099,68 @@ class TestMinMaxIntegerField(FieldValues):
field = serializers.IntegerField(min_value=1, max_value=3)
class TestBigIntegerField(FieldValues):
"""
Valid and invalid values for `BigIntegerField`.
"""
valid_inputs = {
'1': 1,
'0': 0,
1: 1,
0: 0,
123: 123,
-123: -123,
'999999999999999999999999999': 999999999999999999999999999,
-999999999999999999999999999: -999999999999999999999999999,
1.0: 1,
0.0: 0,
'1.0': 1
}
invalid_inputs = {
0.5: ['A valid biginteger is required.'],
'abc': ['A valid biginteger is required.'],
'0.5': ['A valid biginteger is required.']
}
outputs = {
'1': 1,
'0': 0,
1: 1,
0: 0,
1.0: 1,
0.0: 0,
'999999999999999999999999999': 999999999999999999999999999,
-999999999999999999999999999: -999999999999999999999999999
}
field = serializers.BigIntegerField()
class TestMinMaxBigIntegerField(FieldValues):
"""
Valid and invalid values for `IntegerField` with min and max limits.
"""
valid_inputs = {
'1': 1,
'3': 3,
1: 1,
3: 3,
}
invalid_inputs = {
0: ['Ensure this value is greater than or equal to 1.'],
4: ['Ensure this value is less than or equal to 3.'],
'0': ['Ensure this value is greater than or equal to 1.'],
'4': ['Ensure this value is less than or equal to 3.'],
}
outputs = {}
field = serializers.BigIntegerField(min_value=1, max_value=3)
class TestCoercionBigIntegerField(TestCase):
def test_force_coerce_to_string(self):
field = serializers.BigIntegerField(coerce_to_string=True)
assert isinstance(field.to_representation(int('1')), str)
class TestFloatField(FieldValues):
"""
Valid and invalid values for `FloatField`.

View File

@ -171,7 +171,7 @@ class TestRegularFieldMappings(TestCase):
expected = dedent(r"""
TestSerializer\(\):
auto_field = IntegerField\(read_only=True\)
big_integer_field = IntegerField\(.*\)
big_integer_field = BigIntegerField\(.*\)
boolean_field = BooleanField\(required=False\)
char_field = CharField\(max_length=100\)
comma_separated_integer_field = CharField\(max_length=100, validators=\[<django.core.validators.RegexValidator object>\]\)