CLI tool
django-phonenumber-field/django-phonenumber-field avatar
django-phonenumber-field/django-phonenumber-field

django-phonenumber-field: one phone field that stores numbers in E.164 form

A django model and form field for normalised phone numbers using python-phonenumbers

1,549 stars320 forksPythonMIT

At a glance

What is it?
This Django library wraps python-phonenumbers, a port of Google's libphonenumber, to validate, pretty print, and convert international phone numbers in model and form fields. It requires Django 5.2 or newer and Python 3.10 or newer, and the phone number backend is an optional install rather than a hard dependency.
Who is it for?
django-phonenumber-field fits a Django team that stores phone numbers as data rather than as text, wants E.164 storage with a national format for display, and would rather inherit libphonenumber's metadata than maintain its own country rules. It is the wrong choice if you need to accept malformed input and clean it later, or if you cannot add a phone number parsing dependency to your install.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • django-phonenumber-field/django-phonenumber-field1,549 ★ · +1
Star history
Repository2026-10-162026-10-23
django-phonenumber-field/django-phonenumber-field1.5k1.5k

1 Stars in the last 7 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The library is a thin layer over libphonenumber metadata

django-phonenumber-field is described as a Django library which interfaces with `python-phonenumbers` to validate, pretty print and convert phone numbers. That single sentence describes the whole architecture, and understanding the dependency is more useful than memorising the field API.

`python-phonenumbers` is a port of Google's `libphonenumber` library, which powers Android's phone number handling. The practical consequence is that the validation rules, the country metadata, the numbering plan structure, and the parsing edge cases are not written by this project. They come from a maintained port of the same metadata that mobile platforms use to decide whether a number is possible, valid, or assigned.

This is the whole reason the library exists as a separate package rather than a snippet on a blog. Phone number validation is not a regular expression problem. A number is valid in one country and invalid in another, the same digits can be mobile, fixed, or toll free depending on the numbering plan, and the metadata changes as countries renumber. Delegating that to libphonenumber means the Django package only has to deal with Django: model fields, form fields, and the display format.

The three verbs in the description are worth separating, because they are three different features. Validate answers whether the number is acceptable. Pretty print renders a stored number in a form a human recognises. Convert turns between representations, typically from a national format into the international form used for storage and transmission.

The phone number backend is an optional extra, and that choice has consequences

The dependency setup in pyproject.toml is where the design decisions become concrete.

The only required dependency is `Django>=5.2`. Everything else is optional. There are three extras:

toml
babel = ["Babel"]
phonenumbers = ["phonenumbers >= 7.0.2"]
phonenumberslite = ["phonenumberslite >= 7.0.2"]

The two phone number extras are alternatives, not complements. `phonenumbers` and `phonenumberslite` both require version 7.0.2 or newer, and they are two distributions of the same underlying metadata, one full and one trimmed. The `babel` extra is separate again and is what you would add for locale-aware formatting and parsing of the surrounding text, not for the number metadata itself.

Making the phone number backend optional has a real payoff and a real cost. The payoff is that the package installs cleanly in environments where the metadata is not needed, for example a documentation build or a project that only uses the model field definition without ever parsing a number. The cost is that a mistake in your requirements file produces an import error at runtime rather than a missing dependency at install time, and it is the kind of mistake that only shows up when a user submits a form.

The Python floor is `requires-python = ">=3.10"`, and the classifiers list support for 3.10 through 3.14 on CPython only, marked as Python 3 only. The Django classifiers list 5.2, 6.0, and 6.1, and the project describes itself with a Development Status of 5, Production/Stable.

The supported Django range is narrow and the Python floor is recent

The version floor is a good signal about who the library is for. `Django>=5.2` as the only hard dependency, and Python 3.10 as the minimum, means this package targets current applications rather than maintaining compatibility with older Django releases.

That is a defensible position for a small, stable field library, and it buys something concrete: a much smaller test matrix. The test configuration lives in `tox.ini`, and the documentation says tox needs to be installed, then gives the whole matrix run as a single command:

bash
tox

Running that with the locally available Python interpreters generates a combined coverage report, and the documentation points at the tox cheat sheet for the most useful variants of the command.

The alternative to a narrow matrix is a wide one, and wide matrices are where libraries like this quietly rot. By requiring Python 3.10 and Django 5.2, the project keeps the number of combinations it has to keep working small, and it can afford to test all of them.

The repository layout is correspondingly lean. The package code is in `phonenumber_field/`, the tests in `tests/`, the documentation in `docs/` with a `.readthedocs.yaml` at the root, and the metadata files that a Python package needs: `pyproject.toml`, `CHANGELOG.rst`, `AUTHORS`, `LICENSE`, and `MANIFEST.in`. The distribution name in pyproject.toml is `django-phonenumber-field`, and the version is held in the dynamic version field, meaning it is read from the package source rather than hard coded in the project metadata.

Reading the project docs versus the code

The documentation split is worth understanding before you start using it, because the two halves answer different questions.

The `docs/` directory and the readthedocs configuration hold the user-facing documentation, hosted at django-phonenumber-field.readthedocs.io. That is where the field API, the settings, the form widget behaviour, and the examples live.

The `CHANGELOG.rst` at the root is a separate artefact from the published documentation, and for a library of this size it is often the more informative file. The release history shows a steady cadence: 8.3.0 in October 2025, 8.4.0 in November 2025, and 8.5.0 in July 2026, with the last push to the repository on 2026-10-11. The version numbers crossing into the 8.x range tell you the API has been stable for a long time, which for a form field is the point.

The `AUTHORS` file is present as well, and the project metadata names two authors, Stefan Foulis and François Freitag, with the latter as a maintainer alongside the former. Two named maintainers for a focused field library is a reasonable ratio, and it tells you the package is not a side project of a much larger codebase.

For a task like this, the practical order is to read the documentation for the field's options, check the changelog before upgrading to see whether a behaviour you rely on changed, and then read the `phonenumber_field/` source when the documentation is ambiguous about a specific validation case.

Where this field is the wrong tool

The limits are narrow but they are real, and they come from the fact that the library's job is to be strict.

The first is that validation is the gate. If your product wants to accept whatever a customer types and clean it up later, this field is the wrong tool, because the field's purpose is to refuse numbers that do not parse. A form that rejects a valid number that libphonenumber does not recognise is a support burden, and one that accepts a number formatted oddly is a data quality problem. Both directions are consequences of delegating to libphonenumber's metadata rather than to a looser rule.

The second is the dependency. Adding a phone number parsing library means shipping a metadata database, and the full `phonenumbers` extra is the larger of the two. That is a reasonable trade for a system that treats phone numbers as important, and an unnecessary one for a project with a single contact form. The `phonenumberslite` extra exists for exactly that case, and the choice between them is a decision the project leaves open rather than making for you.

The third is scope. This is a model and form field. It is not a delivery service, it does not verify that a number is reachable, and it does not tell you whether a number is assigned to a person or a business. libphonenumber can distinguish valid from possible, and that is where its usefulness stops.

The fourth is migration. If you already store phone numbers as strings in a model, switching to this field means deciding how the existing rows are handled. A number stored in a national format cannot be normalised without knowing the country, and a field that normalises on save needs the country to be present. That is a data migration with a genuine failure mode, and the documentation is where you will look for how the field handles it, because the field's own behaviour cannot invent the missing information.

Editorial conclusion

django-phonenumber-field fits a Django team that stores phone numbers as data rather than as text, wants E.164 storage with a national format for display, and would rather inherit libphonenumber's metadata than maintain its own country rules. It is the wrong choice if you need to accept malformed input and clean it later, or if you cannot add a phone number parsing dependency to your install. Check three things before adopting it: that your Django version is 5.2 or newer and your Python is 3.10 or newer, that you pick the `phonenumbers` or `phonenumberslite` extra rather than assuming a backend is installed, and that your existing rows are migrated, because a field that stores normalised numbers is a schema and data decision rather than a drop-in swap.

Frequently asked questions

What does django-phonenumber-field do and what does it depend on?

It is a Django model and form field for normalised phone numbers that validates, pretty prints, and converts international numbers. It interfaces with `python-phonenumbers`, a port of Google's `libphonenumber` which powers Android's phone number handling, and its only required dependency is `Django>=5.2`.

How do I install django-phonenumber-field with phone number support?

The package requires Python 3.10 or newer and Django 5.2 or newer. The phone number backend is an optional extra rather than a hard dependency, with `phonenumbers = ["phonenumbers >= 7.0.2"]` and `phonenumberslite = ["phonenumberslite >= 7.0.2"]` as the two alternatives, and `babel = ["Babel"]` as a separate extra for locale aware formatting.

How do I run the django-phonenumber-field test suite?

Tox needs to be installed, then the command `tox` runs the whole test matrix with the locally available Python interpreters and generates a combined coverage report. The test configuration lives in `tox.ini` at the root of the repository.

Which Django and Python versions does django-phonenumber-field support?

The package metadata lists Django 5.2, 6.0, and 6.1 in the framework classifiers and requires `Django>=5.2`, with `requires-python = ">=3.10"` and classifiers for CPython 3.10 through 3.14. The newest release is 8.5.0 from 2026-07-20 and the last push was on 2026-10-11.

Official sources

  1. django-phonenumber-field/django-phonenumber-field on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/django-phonenumber-field-django-phonenumber-field.svg)](https://hysenlabs.com/projects/django-phonenumber-field-django-phonenumber-field)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/django-phonenumber-field-django-phonenumber-field.svg)](https://hysenlabs.com/projects/django-phonenumber-field-django-phonenumber-field)

Was this useful?