django-phonenumber-field
A Django model and form field for validating, storing, and formatting international phone numbers via libphonenumber.
Repository Health
Technical Analysis
django-phonenumber-field is a Django library that wraps Google’s libphonenumber engine (via the python-phonenumbers port) into a first-class Django model field, form field, and DRF serializer field. It parses, validates, normalizes, and formats international phone numbers so applications don’t need to hand-roll regex-based validation or manage country-specific formatting rules themselves.
The library exposes a PhoneNumberField for Django models that stores numbers in a configurable canonical format (E164 by default), a matching form field with region-aware widgets including a country-prefix picker, and a PhoneNumber class that extends phonenumbers.PhoneNumber with convenient properties like as_international, as_e164, and as_national. Maintained since 2011, it’s a common dependency in Django projects that collect phone numbers, from user profiles to two-factor authentication flows.
What You Get
- Django model field (
PhoneNumberField) that validates and stores phone numbers in a configurable canonical format - Matching Django form field with automatic validation and region-aware widgets
PhoneNumberPrefixWidgetfor split country-code + national-number inputRegionalPhoneNumberWidgetthat displays numbers in national format when they match the configured region- Django REST Framework serializer field for API validation
PhoneNumbervalue object with formatting helpers (as_international,as_e164,as_national,as_rfc3966)- Optional Babel integration for localized formatting
Common Use Cases
- Validating and storing user phone numbers on Django user/profile models
- Collecting phone numbers in Django forms with country-aware input widgets
- Exposing phone number fields through Django REST Framework APIs
- Normalizing inconsistently formatted phone numbers from CSV imports or third-party data before storage
- Enforcing region-specific phone number formats for a single-country application via
PHONENUMBER_DEFAULT_REGION
Under The Hood
Architecture
The library is organized around a small set of focused modules: phonenumber.py defines a PhoneNumber value object subclassing phonenumbers.PhoneNumber with pythonic formatting properties and custom equality/ordering that compares canonical string representations; modelfields.py defines PhoneNumberField(models.CharField) plus a PhoneNumberDescriptor that coerces assigned values through to_python() on __set__; formfields.py and widgets.py layer Django forms integration (including a MultiWidget-based country-prefix picker) on top of the same conversion logic; serializerfields.py adapts the same validation for Django REST Framework. All entry points funnel through the shared to_python()/PhoneNumber.from_string() functions in phonenumber.py, so parsing and normalization behavior stays consistent across models, forms, and serializers — a change to that core module propagates everywhere numbers are handled.
Tech Stack
Pure Python (3.10+) with Django 5.2+ as a required dependency and phonenumbers (or the lighter phonenumberslite) as an optional extra providing the actual libphonenumber parsing/validation/formatting engine. Packaging uses setuptools with setuptools_scm for git-tag-derived versioning, and an optional Babel extra enables locale-aware number formatting. No database driver or web framework beyond Django itself; the library is a thin, dependency-light integration layer.
Code Quality
The project has a substantial test suite (tests/test_phonenumber.py, test_formfields.py, test_widgets.py, test_serializers.py, plus a general tests.py) covering model field behavior, form validation, widget rendering, and DRF serialization, run across the Python/Django support matrix via tox with combined coverage reporting and CI (GitHub Actions Test workflow, badge in the README). Code style is enforced with ruff (pyflakes, pycodestyle, isort, bugbear, comprehensions, pyupgrade rules configured in pyproject.toml). Naming and error handling are explicit and idiomatic Django (custom checks.Error integration for configuration validation, typed exceptions like TypeError/ValueError for invalid conversions).
What Makes It Unique Rather than validating phone numbers with regex heuristics, it delegates entirely to Google’s libphonenumber (the same engine behind Android’s phone number handling) for parsing and validation, then wraps that engine’s output in Django-native abstractions — a model field with a real value-object descriptor, a DRF serializer field, and multiple widget strategies (split country-code input, region-aware national-format display) that most hand-rolled phone validation implementations don’t attempt to replicate.