diff --git a/phonenumber_field/serializerfields.py b/phonenumber_field/serializerfields.py index 2502a57a..2fe66ae4 100644 --- a/phonenumber_field/serializerfields.py +++ b/phonenumber_field/serializerfields.py @@ -1,16 +1,22 @@ +from django.conf import settings from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from rest_framework.exceptions import ValidationError -from phonenumber_field.phonenumber import to_python +from phonenumber_field.phonenumber import to_python, validate_region class PhoneNumberField(serializers.CharField): default_error_messages = {"invalid": _("Enter a valid phone number.")} + def __init__(self, *args, region=None, **kwargs): + super().__init__(*args, **kwargs) + validate_region(region) + self.region = region or getattr(settings, "PHONENUMBER_DEFAULT_REGION", None) + def to_internal_value(self, data): str_value = super().to_internal_value(data) - phone_number = to_python(str_value) + phone_number = to_python(str_value, region=self.region) if phone_number and not phone_number.is_valid(): raise ValidationError(self.error_messages["invalid"]) return phone_number diff --git a/tests/test_serializers.py b/tests/test_serializers.py index 2d02f401..ab06834f 100644 --- a/tests/test_serializers.py +++ b/tests/test_serializers.py @@ -1,6 +1,7 @@ -from django.test import SimpleTestCase +from django.test import SimpleTestCase, override_settings from rest_framework import serializers +from phonenumber_field.phonenumber import PhoneNumber from phonenumber_field.serializerfields import PhoneNumberField from .models import OptionalPhoneNumber @@ -25,3 +26,74 @@ class PhoneNumberSerializer(serializers.Serializer): s = PhoneNumberSerializer(data={"phone": 1}) self.assertIs(s.is_valid(), False) + + def test_empty_required(self): + class PhoneNumberSerializer(serializers.Serializer): + phone = PhoneNumberField() + + serializer = PhoneNumberSerializer(data={"phone": ""}) + self.assertIs(serializer.is_valid(), False) + self.assertEqual(serializer.validated_data, {}) + + def test_empty_optional(self): + class PhoneNumberSerializer(serializers.Serializer): + phone = PhoneNumberField(allow_blank=True) + + serializer = PhoneNumberSerializer(data={"phone": ""}) + self.assertIs(serializer.is_valid(), True) + self.assertEqual(serializer.validated_data, {"phone": ""}) + + def test_e164_phone_number(self): + class PhoneNumberSerializer(serializers.Serializer): + phone = PhoneNumberField() + + serializer = PhoneNumberSerializer(data={"phone": "+33612345678"}) + self.assertIs(serializer.is_valid(), True) + self.assertEqual(serializer.validated_data, {"phone": "+33612345678"}) + self.assertIsInstance(serializer.validated_data["phone"], PhoneNumber) + + def test_region(self): + class PhoneNumberSerializer(serializers.Serializer): + phone = PhoneNumberField(region="FR") + + serializer = PhoneNumberSerializer(data={"phone": "0612345678"}) + self.assertIs(serializer.is_valid(), True) + self.assertEqual(serializer.validated_data, {"phone": "+33612345678"}) + self.assertIsInstance(serializer.validated_data["phone"], PhoneNumber) + + def test_region_invalid(self): + class PhoneNumberSerializer(serializers.Serializer): + phone = PhoneNumberField(region="GB") + + serializer = PhoneNumberSerializer(data={"phone": "0612345678"}) + self.assertIs(serializer.is_valid(), False) + self.assertEqual(serializer.validated_data, {}) + self.assertEqual(serializer.errors, {"phone": ["Enter a valid phone number."]}) + + @override_settings(PHONENUMBER_DEFAULT_REGION="FR") + def test_region_from_settings(self): + class PhoneNumberSerializer(serializers.Serializer): + phone = PhoneNumberField() + + serializer = PhoneNumberSerializer(data={"phone": "0612345678"}) + self.assertIs(serializer.is_valid(), True) + self.assertEqual(serializer.validated_data, {"phone": "+33612345678"}) + self.assertIsInstance(serializer.validated_data["phone"], PhoneNumber) + + @override_settings(PHONENUMBER_DEFAULT_REGION="GB") + def test_region_kwarg_precedes_setting(self): + class PhoneNumberSerializer(serializers.Serializer): + phone = PhoneNumberField(region="FR") + + serializer = PhoneNumberSerializer(data={"phone": "0612345678"}) + self.assertIs(serializer.is_valid(), True) + self.assertEqual(serializer.validated_data, {"phone": "+33612345678"}) + self.assertIsInstance(serializer.validated_data["phone"], PhoneNumber) + + def test_invalid_region(self): + with self.assertRaisesMessage( + ValueError, "“INVALID” is not a valid region code. Choices are" + ): + + class PhoneNumberSerializer(serializers.Serializer): + phone = PhoneNumberField(region="INVALID")