From 6ac499e6fbb78ea22e7eebfca3b3c25aff8f7423 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 | 76 ++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/phonenumber_field/serializerfields.py b/phonenumber_field/serializerfields.py index d0a0a380..d0c42754 100644 --- a/phonenumber_field/serializerfields.py +++ b/phonenumber_field/serializerfields.py @@ -1,15 +1,21 @@ +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): - phone_number = to_python(data) + phone_number = to_python(data, 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 6bb9883c..bd02dd4e 100644 --- a/tests/test_serializers.py +++ b/tests/test_serializers.py @@ -1,6 +1,9 @@ -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 @@ -16,3 +19,74 @@ class Meta: s = PhoneNumberSerializer(data=data) self.assertIs(s.is_valid(), True) self.assertEqual(s.data, {}) + + 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")