Django Phone Number Field
django-phonenumber-field is a Django library that integrates Google's `libphonenumber` (via `python-phonenumbers`) to provide an international phone number field for Django models and forms. It handles validation, formatting, and conversion of phone numbers according to international standards. The current version is 8.4.0, and the library maintains an active release cadence with multiple minor/patch releases throughout the year.
Warnings
- breaking The `PhoneNumberInternationalFallbackWidget` was removed in version 8.0.0. If you were using it, you should switch to `phonenumber_field.widgets.RegionalPhoneNumberWidget` instead.
- breaking In version 8.0.0, validation logic was moved from widgets to form fields. This changes how custom validation on `PhoneNumberField`s works. If you had `clean_FIELD()` or `clean()` methods that relied on the widget's previous validation behavior, you may need to review and adjust them. Error codes like `invalid_phone_number` might need to be changed to `invalid`.
- breaking Version 7.2.0 introduced a database converter for the model field. This change, though intended as a fix for `values_list()` behavior, was retrospectively considered a breaking change as it could affect existing code.
- gotcha The `PHONENUMBER_DEFAULT_REGION` setting is critical for the library to correctly interpret and validate national phone numbers. Without it, numbers in 'NATIONAL' format may not be recognized or validated properly.
- gotcha When using `SplitPhoneNumberField` (which renders a separate input for the prefix and the national number), applying default CSS frameworks like Bootstrap might cause the prefix and number fields to display on separate lines instead of inline.
- gotcha While `PhoneNumberField` is based on `CharField` internally, it stores and retrieves `PhoneNumber` objects, not plain strings. When directly assigning a string value to a `PhoneNumberField` in Python code (e.g., `model_instance.phone_number = '+1234567890'`), the string must include the country code for correct parsing and validation.
Install
-
pip install django-phonenumber-field[phonenumbers] -
pip install django-phonenumber-field[phonenumberslite]
Imports
- PhoneNumberField
from phonenumber_field.modelfields import PhoneNumberField
- PhoneNumberField (form field)
from phonenumber_field.formfields import PhoneNumberField
- SplitPhoneNumberField (form field for prefix/number split input)
from phonenumber_field.formfields import SplitPhoneNumberField
- PhoneNumber
from phonenumber_field.phonenumber import PhoneNumber
- RegionalPhoneNumberWidget
from phonenumber_field.widgets import RegionalPhoneNumberWidget
Quickstart
import os
import django
from django.conf import settings
from django.db import models
from phonenumber_field.modelfields import PhoneNumberField
settings.configure(
INSTALLED_APPS=['phonenumber_field'],
DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}},
PHONENUMBER_DEFAULT_REGION='US' # Crucial for national formats
)
django.setup()
class Contact(models.Model):
name = models.CharField(max_length=100)
phone_number = PhoneNumberField(blank=True)
def __str__(self):
return f"{self.name}: {self.phone_number}"
# Example Usage:
# from django.core.management import call_command
# call_command('makemigrations', 'myapp') # if using in a real app
# call_command('migrate') # if using in a real app
contact1 = Contact.objects.create(name="Alice", phone_number="+12025550123")
contact2 = Contact.objects.create(name="Bob", phone_number="6502530000") # Assumes PHONENUMBER_DEFAULT_REGION='US'
print(contact1)
print(contact2)
print(contact1.phone_number.as_e164)
print(contact2.phone_number.as_national)
# Example with an invalid number (will raise ValidationError in a real form/model save)
# try:
# Contact.objects.create(name="Invalid", phone_number="123")
# except Exception as e:
# print(f"Caught expected error: {e}")