Skip to content

Commit 76da570

Browse files
Support max_length argument for SplitPhoneNumberField
Allow using the field with `fields_for_model`, `ModelForm`, …
1 parent 23d72e9 commit 76da570

File tree

3 files changed

+68
-2
lines changed

3 files changed

+68
-2
lines changed

phonenumber_field/formfields.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,14 @@ class SplitPhoneNumberField(MultiValueField):
105105
widget = widgets.PhoneNumberPrefixWidget
106106

107107
def __init__(
108-
self, *, initial=None, region=None, widget=None, empty_value="", **kwargs
108+
self,
109+
*,
110+
initial=None,
111+
region=None,
112+
widget=None,
113+
empty_value="",
114+
max_length=None,
115+
**kwargs,
109116
):
110117
"""
111118
:keyword list initial: A two-elements iterable:
@@ -125,6 +132,8 @@ def __init__(
125132
:keyword ~django.forms.MultiWidget widget: defaults to
126133
:class:`~phonenumber_field.widgets.PhoneNumberPrefixWidget`
127134
:keyword empty_value: value to use when the field is empty
135+
:keyword int max_length: maximum length of the phone number, when
136+
represented as :setting:`PHONENUMBER_DB_FORMAT`.
128137
"""
129138
validate_region(region)
130139
region = region or getattr(settings, "PHONENUMBER_DEFAULT_REGION", None)
@@ -136,6 +145,7 @@ def __init__(
136145
if widget is None:
137146
widget = self.widget((prefix_field.widget, number_field.widget))
138147
self.empty_value = empty_value
148+
self.max_length = max_length
139149
super().__init__(fields, initial=initial, widget=widget, **kwargs)
140150

141151
def prefix_field(self):
@@ -192,4 +202,19 @@ def clean(self, value):
192202
error_message,
193203
example_number=example_number,
194204
)
195-
return super().clean(value)
205+
clean_value = super().clean(value)
206+
if self.max_length is not None:
207+
phonenumber_str = clean_value.format_as(
208+
getattr(settings, "PHONENUMBER_DB_FORMAT", "E164")
209+
)
210+
if len(phonenumber_str) > self.max_length:
211+
raise ValidationError(
212+
format_lazy(
213+
"Ensure this value has no more than {max_length} characters, "
214+
"“{value}” is {length} characters long.",
215+
max_length=self.max_length,
216+
value=phonenumber_str,
217+
length=len(phonenumber_str),
218+
)
219+
)
220+
return clean_value

tests/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,7 @@ class FrenchPhoneOwner(models.Model):
104104

105105
class TestModelRegionAR(models.Model):
106106
phone = PhoneNumberField(region="AR", blank=True, null=True)
107+
108+
109+
class PhoneNumberWithMaxLength(models.Model):
110+
phone = PhoneNumberField(max_length=3)

tests/test_formfields.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from phonenumber_field.formfields import PhoneNumberField, SplitPhoneNumberField
1313
from phonenumber_field.phonenumber import PhoneNumber
1414
from phonenumber_field.validators import validate_phonenumber
15+
from tests.models import NullablePhoneNumber, PhoneNumberWithMaxLength
1516

1617
ALGERIAN_PHONE_NUMBER = "+213799136332"
1718

@@ -708,3 +709,39 @@ class TestForm(forms.Form):
708709

709710
form = TestForm({"phone_0": "FR", "phone_1": "1010"})
710711
self.assertIs(form.is_valid(), True)
712+
713+
def test_formfield_with_maxlength_null(self):
714+
class TestForm(forms.Form):
715+
def __init__(self, *args, **kwargs):
716+
super().__init__(*args, **kwargs)
717+
self.fields = forms.fields_for_model(
718+
NullablePhoneNumber,
719+
["phone_number"],
720+
field_classes={"phone_number": SplitPhoneNumberField},
721+
)
722+
723+
form = TestForm(data={"phone_number_0": "FR", "phone_number_1": "612345678"})
724+
self.assertIs(form.is_valid(), True)
725+
self.assertEqual(form.cleaned_data["phone_number"], "+33612345678")
726+
727+
def test_formfield_with_max_length(self):
728+
class TestForm(forms.Form):
729+
def __init__(self, *args, **kwargs):
730+
super().__init__(*args, **kwargs)
731+
self.fields = forms.fields_for_model(
732+
PhoneNumberWithMaxLength,
733+
["phone"],
734+
field_classes={"phone": SplitPhoneNumberField},
735+
)
736+
737+
form = TestForm(data={"phone_0": "FR", "phone_1": "33612345678"})
738+
self.assertIs(form.is_valid(), False)
739+
self.assertEqual(
740+
form.errors,
741+
{
742+
"phone": [
743+
"Ensure this value has no more than 3 characters, "
744+
"“6 12 34 56 78” is 13 characters long."
745+
],
746+
},
747+
)

0 commit comments

Comments
 (0)