From 1f012e4f172b1814fdaa240800dbd0014df6e6d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Freitag?= Date: Fri, 26 Aug 2022 17:52:18 +0200 Subject: [PATCH] Implement region argument for serializerfields The region argument was implemented for the database field and form field, but not the Django REST framework serializers. Align the serializer with the other fields. Add a bunch of tests for that field. --- phonenumber_field/serializerfields.py | 10 +++- tests/test_serializers.py | 74 ++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 3 deletions(-) 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")