mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-01-23 15:54:16 +03:00
Merge pull request #3008 from linovia/feature/ipaddress-fix
`IPAddressField` improvements
This commit is contained in:
commit
a3d6601e09
|
@ -192,6 +192,17 @@ A field that ensures the input is a valid UUID string. The `to_internal_value` m
|
|||
- `'urn'` - RFC 4122 URN representation of the UUID: `"urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"`
|
||||
Changing the `format` parameters only affects representation values. All formats are accepted by `to_internal_value`
|
||||
|
||||
## IPAddressField
|
||||
|
||||
A field that ensures the input is a valid IPv4 or IPv6 string.
|
||||
|
||||
Corresponds to `django.forms.fields.IPAddressField` and `django.forms.fields.GenericIPAddressField`.
|
||||
|
||||
**Signature**: `IPAddressField(protocol='both', unpack_ipv4=False, **options)`
|
||||
|
||||
- `protocol` Limits valid inputs to the specified protocol. Accepted values are 'both' (default), 'IPv4' or 'IPv6'. Matching is case insensitive.
|
||||
- `unpack_ipv4` Unpacks IPv4 mapped addresses like ::ffff:192.0.2.1. If this option is enabled that address would be unpacked to 192.0.2.1. Default is disabled. Can only be used when protocol is set to 'both'.
|
||||
|
||||
---
|
||||
|
||||
# Numeric fields
|
||||
|
|
|
@ -2,12 +2,13 @@ from __future__ import unicode_literals
|
|||
from django.conf import settings
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||
from django.core.validators import RegexValidator
|
||||
from django.core.validators import RegexValidator, ip_address_validators
|
||||
from django.forms import ImageField as DjangoImageField
|
||||
from django.utils import six, timezone
|
||||
from django.utils.dateparse import parse_date, parse_datetime, parse_time
|
||||
from django.utils.encoding import is_protected_type, smart_text
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.ipv6 import clean_ipv6_address
|
||||
from rest_framework import ISO_8601
|
||||
from rest_framework.compat import (
|
||||
EmailValidator, MinValueValidator, MaxValueValidator,
|
||||
|
@ -672,6 +673,31 @@ class UUIDField(Field):
|
|||
return getattr(value, self.uuid_format)
|
||||
|
||||
|
||||
class IPAddressField(CharField):
|
||||
"""Support both IPAddressField and GenericIPAddressField"""
|
||||
|
||||
default_error_messages = {
|
||||
'invalid': _('Enter a valid IPv4 or IPv6 address.'),
|
||||
}
|
||||
|
||||
def __init__(self, protocol='both', **kwargs):
|
||||
self.protocol = protocol.lower()
|
||||
self.unpack_ipv4 = (self.protocol == 'both')
|
||||
super(IPAddressField, self).__init__(**kwargs)
|
||||
validators, error_message = ip_address_validators(protocol, self.unpack_ipv4)
|
||||
self.validators.extend(validators)
|
||||
|
||||
def to_internal_value(self, data):
|
||||
if data and ':' in data:
|
||||
try:
|
||||
if self.protocol in ('both', 'ipv6'):
|
||||
return clean_ipv6_address(data, self.unpack_ipv4)
|
||||
except DjangoValidationError:
|
||||
self.fail('invalid', value=data)
|
||||
|
||||
return super(IPAddressField, self).to_internal_value(data)
|
||||
|
||||
|
||||
# Number types...
|
||||
|
||||
class IntegerField(Field):
|
||||
|
|
|
@ -734,6 +734,7 @@ class ModelSerializer(Serializer):
|
|||
models.TextField: CharField,
|
||||
models.TimeField: TimeField,
|
||||
models.URLField: URLField,
|
||||
models.GenericIPAddressField: IPAddressField,
|
||||
}
|
||||
if ModelDurationField is not None:
|
||||
serializer_field_mapping[ModelDurationField] = DurationField
|
||||
|
@ -1360,6 +1361,10 @@ class ModelSerializer(Serializer):
|
|||
if hasattr(models, 'UUIDField'):
|
||||
ModelSerializer.serializer_field_mapping[models.UUIDField] = UUIDField
|
||||
|
||||
# IPAddressField is deprecated in Django
|
||||
if hasattr(models, 'IPAddressField'):
|
||||
ModelSerializer.serializer_field_mapping[models.IPAddressField] = IPAddressField
|
||||
|
||||
if postgres_fields:
|
||||
class CharMappingField(DictField):
|
||||
child = CharField()
|
||||
|
|
|
@ -549,6 +549,60 @@ class TestUUIDField(FieldValues):
|
|||
self._test_format('hex', '0' * 32)
|
||||
|
||||
|
||||
class TestIPAddressField(FieldValues):
|
||||
"""
|
||||
Valid and invalid values for `IPAddressField`
|
||||
"""
|
||||
valid_inputs = {
|
||||
'127.0.0.1': '127.0.0.1',
|
||||
'192.168.33.255': '192.168.33.255',
|
||||
'2001:0db8:85a3:0042:1000:8a2e:0370:7334': '2001:db8:85a3:42:1000:8a2e:370:7334',
|
||||
'2001:cdba:0:0:0:0:3257:9652': '2001:cdba::3257:9652',
|
||||
'2001:cdba::3257:9652': '2001:cdba::3257:9652'
|
||||
}
|
||||
invalid_inputs = {
|
||||
'127001': ['Enter a valid IPv4 or IPv6 address.'],
|
||||
'127.122.111.2231': ['Enter a valid IPv4 or IPv6 address.'],
|
||||
'2001:::9652': ['Enter a valid IPv4 or IPv6 address.'],
|
||||
'2001:0db8:85a3:0042:1000:8a2e:0370:73341': ['Enter a valid IPv4 or IPv6 address.'],
|
||||
}
|
||||
outputs = {}
|
||||
field = serializers.IPAddressField()
|
||||
|
||||
|
||||
class TestIPv4AddressField(FieldValues):
|
||||
"""
|
||||
Valid and invalid values for `IPAddressField`
|
||||
"""
|
||||
valid_inputs = {
|
||||
'127.0.0.1': '127.0.0.1',
|
||||
'192.168.33.255': '192.168.33.255',
|
||||
}
|
||||
invalid_inputs = {
|
||||
'127001': ['Enter a valid IPv4 address.'],
|
||||
'127.122.111.2231': ['Enter a valid IPv4 address.'],
|
||||
}
|
||||
outputs = {}
|
||||
field = serializers.IPAddressField(protocol='IPv4')
|
||||
|
||||
|
||||
class TestIPv6AddressField(FieldValues):
|
||||
"""
|
||||
Valid and invalid values for `IPAddressField`
|
||||
"""
|
||||
valid_inputs = {
|
||||
'2001:0db8:85a3:0042:1000:8a2e:0370:7334': '2001:db8:85a3:42:1000:8a2e:370:7334',
|
||||
'2001:cdba:0:0:0:0:3257:9652': '2001:cdba::3257:9652',
|
||||
'2001:cdba::3257:9652': '2001:cdba::3257:9652'
|
||||
}
|
||||
invalid_inputs = {
|
||||
'2001:::9652': ['Enter a valid IPv4 or IPv6 address.'],
|
||||
'2001:0db8:85a3:0042:1000:8a2e:0370:73341': ['Enter a valid IPv4 or IPv6 address.'],
|
||||
}
|
||||
outputs = {}
|
||||
field = serializers.IPAddressField(protocol='IPv6')
|
||||
|
||||
|
||||
# Number types...
|
||||
|
||||
class TestIntegerField(FieldValues):
|
||||
|
|
Loading…
Reference in New Issue
Block a user