The PhoneNumber wrapper
- class phonenumber_field.phonenumber.PhoneNumber
A extended version of phonenumbers.PhoneNumber that provides some neat and more pythonic, easy to access methods. This makes using a PhoneNumber instance much easier, especially in templates and such.
- classmethod from_string(phone_number, region=None) Self
- Parameters:
region (str) – 2-letter country code as defined in ISO 3166-1. When not supplied, defaults to
PHONENUMBER_DEFAULT_REGION
- is_valid()
Whether the number supplied is actually valid.
- Returns:
True
when the phone number is valid.- Return type:
- property as_international
- property as_national
- property as_e164
- property as_rfc3966
Usage
>>> from phonenumber_field.phonenumber import PhoneNumber
>>> number = PhoneNumber.from_string("+16044011234")
>>> print(number.as_national)
(604) 401-1234
>>> print(number.as_e164)
+16044011234
>>> print(number.as_international)
+1 604-401-1234
>>> print(number.as_rfc3966)
tel:+1-604-401-1234
# Using national numbers with the region keyword argument.
>>> canadian_number = "(604) 401 1234"
>>> number = PhoneNumber.from_string(canadian_number, region="CA")
>>> print(number.as_e164)
+16044011234
Model field
The PhoneNumberField
model field allows storing
PhoneNumber
s in the database, based
on a CharField
.
The phone number format used by the database is controlled with
PHONENUMBER_DB_FORMAT
. When no region is specified, a phone number
in the "NATIONAL"
format will be assumed to be from the
PHONENUMBER_DEFAULT_REGION
.
The default form field for this field is the
PhoneNumberField
.The default form widget for this field is the
RegionalPhoneNumberWidget
.
- class phonenumber_field.modelfields.PhoneNumberField(*args, region=None, **kwargs)
- __init__(*args, region=None, **kwargs)
- Parameters:
region (str) – 2-letter country code as defined in ISO 3166-1. When not supplied, defaults to
PHONENUMBER_DEFAULT_REGION
max_length (int) – The maximum length of the underlying char field.
Usage
from django.db import models
from phonenumber_field.modelfields import PhoneNumberField
class Customer(models.Model):
name = models.TextField()
# An optional phone number.
phone_number = PhoneNumberField(blank=True)
Form fields
PhoneNumberField
The PhoneNumberField
form field to validate
PhoneNumber
, based on a
CharField
.
Default widget:
RegionalPhoneNumberWidget
Empty value:
""
Normalizes to: A
PhoneNumber
or an emptystr
(""
)
- class phonenumber_field.formfields.PhoneNumberField(*args, region=None, widget=None, **kwargs)
- __init__(*args, region=None, widget=None, **kwargs)
- Parameters:
region (str) – 2-letter country code as defined in ISO 3166-1. When not supplied, defaults to
PHONENUMBER_DEFAULT_REGION
widget (django.forms.Widget) – defaults to
RegionalPhoneNumberWidget
Usage
>>> from phonenumber_field.formfields import PhoneNumberField
>>> class PhoneForm(django.forms.Form):
... number = PhoneNumberField(region="CA")
...
# Manipulating data
>>> form = PhoneForm({"number": "+1 604 401 1234"})
>>> form.is_valid()
True
>>> form.cleaned_data
{'number': PhoneNumber(country_code=1, national_number=6044011234, extension=None, italian_leading_zero=None, number_of_leading_zeros=None, country_code_source=1, preferred_domestic_carrier_code=None)}
>>> print_html(form.as_div())
<div>
<label for="id_number">
Number:
</label>
<input id="id_number" name="number" required="" type="tel" value="(604) 401-1234"/>
</div>
# Handling errors
>>> form = PhoneForm({"number": "invalid"})
>>> form.is_valid()
False
>>> print_html(form.as_div())
<div>
<label for="id_number">
Number:
</label>
<ul class="errorlist" id="id_number_error">
<li>
Enter a valid phone number (e.g. (506) 234-5678) or a number with an international call prefix.
</li>
</ul>
<input aria-describedby="id_number_error" aria-invalid="true" id="id_number" name="number" required="" type="tel" value="invalid"/>
</div>
Note
Because the PhoneNumberField specifies a region, the example number is a national number from that region. When no region is specified, an international example phone number in the E.164 format is suggested.
SplitPhoneNumberField
A MultiValueField
that offers:
a
<select … >
element to choose the region, andan
<input type="tel" … >
to enter the phone number.
To customize each field, subclass
SplitPhoneNumberField
and override:
prefix_field()
for the phone number prefix field,number_field()
for the phone number field.
This widget uses an example phone number from the selected region for the
invalid
key in error_messages
, when the region
choice is valid.
To customize the dynamic message, use
phonenumber_field.formfields.SplitPhoneNumberField.invalid_error_message()
.
Important
Requires the Babel package.
- class phonenumber_field.formfields.SplitPhoneNumberField(*, initial=None, region=None, widget=None, **kwargs)
- __init__(*, initial=None, region=None, widget=None, **kwargs)
- Parameters:
initial (list) –
A two-elements iterable:
the region code, an
str
, the 2-letter country code as defined in ISO 3166-1.the phone number, an
str
When
initial
is not provided, theregion
keyword argument is used as the initial for the region field if specified, otherwisePHONENUMBER_DEFAULT_REGION
is used.region (str) – 2-letter country code as defined in ISO 3166-1. When not supplied, defaults to
PHONENUMBER_DEFAULT_REGION
widget (MultiWidget) – defaults to
PhoneNumberPrefixWidget
- prefix_field()
Returns the default
Field
for the phone number prefix field.Use this hook to set widget attributes or update the field definition.
- number_field()
Returns the default
Field
for the phone number field.Use this hook to set widget attributes or update the field definition.
- invalid_error_message()
Hook to customize
error_messages["invalid"]
for a given region.Include the example number in the message with the
{example_number}
placeholder.
Usage
Simple
>>> from phonenumber_field.formfields import SplitPhoneNumberField
>>> class PhoneForm(django.forms.Form):
... number = SplitPhoneNumberField()
...
>>> form = PhoneForm()
>>> print_html_compact(form.as_div())
<div>
<fieldset>
<legend>
Number:
</legend>
<select id="id_number_0" name="number_0" required="">
<option selected="" value="">
---------
</option>
<option value="AF">
Afghanistan +93
</option>
<option value="AL">
Albania +355
</option>
...
<option value="AX">
Åland Islands +358
</option>
</select>
<input id="id_number_1" name="number_1" required="" type="tel"/>
</fieldset>
</div>
Limiting country choices
>>> from phonenumber_field.formfields import SplitPhoneNumberField
>>> class DemoSplitPhoneNumberField(SplitPhoneNumberField):
... def prefix_field(self):
... return django.forms.ChoiceField(choices=[
... ("", "---------"),
... ("CA", "Canada"),
... ("FR", "France"),
... ])
...
>>> class LimitedCountryPhoneForm(django.forms.Form):
... number = DemoSplitPhoneNumberField()
...
>>> form = LimitedCountryPhoneForm()
>>> print_html(form.as_div())
<div>
<fieldset>
<legend>
Number:
</legend>
<select id="id_number_0" name="number_0" required="">
<option selected="" value="">
---------
</option>
<option value="CA">
Canada
</option>
<option value="FR">
France
</option>
</select>
<input id="id_number_1" name="number_1" required="" type="tel"/>
</fieldset>
</div>
Pre-selecting a country
>>> from phonenumber_field.formfields import SplitPhoneNumberField
>>> class DemoSplitPhoneNumberField(SplitPhoneNumberField):
... def prefix_field(self):
... return django.forms.ChoiceField(choices=[
... ("", "---------"),
... ("CA", "Canada"),
... ("FR", "France"),
... ])
...
>>> class FrenchPhoneForm(django.forms.Form):
... number = DemoSplitPhoneNumberField(region="FR")
...
>>> form = FrenchPhoneForm()
>>> print_html(form.as_div())
<div>
<fieldset>
<legend>
Number:
</legend>
<select id="id_number_0" name="number_0" required="">
<option value="">
---------
</option>
<option value="CA">
Canada
</option>
<option selected="" value="FR">
France
</option>
</select>
<input id="id_number_1" name="number_1" required="" type="tel"/>
</fieldset>
</div>
Customizing widget attrs
>>> from phonenumber_field.formfields import SplitPhoneNumberField
>>> class DemoSplitPhoneNumberField(SplitPhoneNumberField):
... def prefix_field(self):
... return django.forms.ChoiceField(choices=[
... ("", "---------"),
... ("CA", "Canada"),
... ("FR", "France"),
... ])
...
... def number_field(self):
... number_field = super().number_field()
... number_field.widget.attrs["class"] = "form-control"
... return number_field
...
>>> class BootstrapPhoneForm(django.forms.Form):
... number = DemoSplitPhoneNumberField()
...
>>> form = BootstrapPhoneForm()
>>> print_html(form.as_div())
<div>
<fieldset>
<legend>
Number:
</legend>
<select id="id_number_0" name="number_0" required="">
<option selected="" value="">
---------
</option>
<option value="CA">
Canada
</option>
<option value="FR">
France
</option>
</select>
<input class="form-control" id="id_number_1" name="number_1" required="" type="tel"/>
</fieldset>
</div>
Widgets
RegionalPhoneNumberWidget
Default widget for PhoneNumberField
.
input_type:
tel
Renders as
<input type="tel" … >
Important
The region should be specified (either per field using the
region
keyword argument, or with the
PHONENUMBER_DEFAULT_REGION
setting) in order to know which
national number format to recognize.
- class phonenumber_field.widgets.RegionalPhoneNumberWidget(region=None, attrs=None)
A
Widget
that prefers displaying numbers in the national format, and falls back toPHONENUMBER_DEFAULT_FORMAT
for international numbers.- __init__(region=None, attrs=None)
- Parameters:
region (str) – 2-letter country code as defined in ISO 3166-1. When not supplied, defaults to
PHONENUMBER_DEFAULT_REGION
attrs (dict) – See
django.forms.Widget.attrs
Usage
>>> from phonenumber_field.formfields import PhoneNumberField
>>> class CanadianPhoneForm(django.forms.Form):
... # RegionalPhoneNumberWidget is the default widget.
... number = PhoneNumberField(region="CA")
...
# Using the national format for the field’s region.
>>> form = CanadianPhoneForm({"number": "+16044011234"})
>>> print_html(form.as_div())
<div>
<label for="id_number">
Number:
</label>
<input id="id_number" name="number" required="" type="tel" value="(604) 401-1234"/>
</div>
# Using E164 for an international number.
>>> french_number = "+33612345678"
>>> form = CanadianPhoneForm({"number": french_number})
>>> print_html(form.as_div())
<div>
<label for="id_number">
Number:
</label>
<input id="id_number" name="number" required="" type="tel" value="+33612345678"/>
</div>
PhoneNumberPrefixWidget
- class phonenumber_field.widgets.PhoneNumberPrefixWidget(widgets, attrs=None)
Companion widget of
SplitPhoneNumberField
.
Serializer field
The PhoneNumberField
serializer
field, based on the
CharField.
The serialization format is controlled by the
PHONENUMBER_DEFAULT_FORMAT
.
- class phonenumber_field.serializerfields.PhoneNumberField(*args, **kwargs)
- __init__(*args, region=None, **kwargs)
- Parameters:
region (str) – 2-letter country code as defined in ISO 3166-1. When not supplied, defaults to
PHONENUMBER_DEFAULT_REGION
Usage
>>> from django.conf import settings
>>> from rest_framework import renderers, serializers
>>> from phonenumber_field.serializerfields import PhoneNumberField
>>> class PhoneNumberSerializer(serializers.Serializer):
... number = PhoneNumberField(region="CA")
...
>>> serializer = PhoneNumberSerializer(data={"number": "604 401 1234"})
>>> serializer.is_valid()
True
>>> serializer.validated_data
{'number': PhoneNumber(country_code=1, national_number=6044011234, extension=None, italian_leading_zero=None, number_of_leading_zeros=None, country_code_source=20, preferred_domestic_carrier_code=None)}
# Using the PHONENUMBER_DEFAULT_FORMAT.
>>> renderers.JSONRenderer().render(serializer.data)
b'{"number":"+16044011234"}'
Validator
Validates:
a
PhoneNumber
instance, oran
str
in an international format (with a prefix), oran
str
that’s a local phone number according toPHONENUMBER_DEFAULT_REGION
.
Note
Not all well-formed phone numbers are valid. The rules to construct phone numbers vary per region of the world.
Falsehoods Programmers Believe About Phone Numbers is a good read.
- phonenumber_field.validators.validate_international_phonenumber(value)
code: "invalid"
Settings
Phone number format choices
Setting value |
International |
Extensions |
Notes |
---|---|---|---|
|
✓ |
❌ |
|
|
✓ |
✓ |
|
|
✓ |
✓ |
|
|
❌ |
✓ |
DISCOURAGED, requires |
Warning
By default, the library uses E.164, the international public
telecommunication numbering plan,
which does not support phone numbers extensions. Set both
PHONENUMBER_DB_FORMAT
and PHONENUMBER_DEFAULT_FORMAT
to an extension-compatible format to handle phone numbers extensions.
PHONENUMBER_DB_FORMAT
Store phone numbers strings in the specified format in the database.
Default: "E164"
.
See Phone number format choices.
Warning
Data loss may occur when changing the DB format.
Phone numbers stored in the database are parsed every time they are loaded from the database.
When switching from a format that can represent extensions to a format that cannot, the extension information is definitely lost.
When using PHONENUMBER_DB_FORMAT
="NATIONAL"
, changing the
PHONENUMBER_DEFAULT_REGION
will cause phone numbers stored in the
database to be interpreted differently, resulting in data corruption.
PHONENUMBER_DEFAULT_FORMAT
String formatting of phone numbers.
Default: "E164"
.
PHONENUMBER_DEFAULT_REGION
ISO-3166-1 two-letter country code indicating how to interpret regional phone numbers.
Default: None
.