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

Overview

django-phonenumber-field

A Django library which interfaces with python-phonenumbers to validate, pretty print and convert phone numbers. python-phonenumbers is a port of Google's libphonenumber library, which powers Android's phone number handling.

Included are:

  • PhoneNumber, a pythonic wrapper around python-phonenumbers' PhoneNumber class
  • PhoneNumberField, a model field
  • PhoneNumberField, a form field
  • PhoneNumberField, a serializer field
  • PhoneNumberPrefixWidget, a form widget for selecting a region code and entering a national number. Requires the Babel package be installed.
  • PhoneNumberInternationalFallbackWidget, a form widget that uses national numbers unless an international number is entered. A PHONENUMBER_DEFAULT_REGION setting needs to be added to your Django settings in order to know which national number format to recognize.

Installation

pip install django-phonenumber-field[phonenumbers]

As an alternative to the phonenumbers package, it is possible to install the phonenumberslite package which has a lower memory footprint.

pip install django-phonenumber-field[phonenumberslite]

Basic usage

First, add phonenumber_field to the list of the installed apps in your settings.py file:

INSTALLED_APPS = [
    ...
    'phonenumber_field',
    ...
]

Then, you can use it like any regular model field:

from phonenumber_field.modelfields import PhoneNumberField

class MyModel(models.Model):
    name = models.CharField(max_length=255)
    phone_number = PhoneNumberField()
    fax_number = PhoneNumberField(blank=True)

Internally, PhoneNumberField is based upon CharField and by default represents the number as a string of an international phonenumber in the database (e.g '+41524204242').

The object returned is a PhoneNumber instance, not a string. If strings are used to initialize it, e.g. via MyModel(phone_number='+41524204242') or form handling, it has to be a phone number with country code.

Settings

PHONENUMBER_DB_FORMAT

Store phone numbers strings in the specified format.

Default: "E164".

Choices:

  • "E164",
  • "INTERNATIONAL",
  • "NATIONAL" (requires PHONENUMBER_DEFAULT_REGION),
  • "RFC3966" (requires PHONENUMBER_DEFAULT_REGION).

PHONENUMBER_DEFAULT_REGION

ISO-3166-1 two-letter country code indicating how to interpret regional phone numbers.

Default: None.

PHONENUMBER_DEFAULT_FORMAT

String formatting of phone numbers.

Default: "E164".

Choices:

  • "E164",
  • "INTERNATIONAL",
  • "NATIONAL",
  • "RFC3966".

Running tests

tox needs to be installed. To run the whole test matrix with the locally available Python interpreters and generate a combined coverage report:

tox

run a specific combination:

tox -e py36-djmain,py39-djmain
Issues
  • test against django 1.11

    test against django 1.11

    opened by thijstriemstra 18
  • Create a new 0.7 version?

    Create a new 0.7 version?

    The 0.6 version has some bugs (like'NoneType' object has no attribute 'as_e164') which are resolved in merges there after, but difficult to get the latest version from pip.

    opened by devangmundhra 15
  • Widget initial by label, not value (country code US does not initialize as United States)

    Widget initial by label, not value (country code US does not initialize as United States)

    I am trying to set the initial value of the Prefix select, the issue is that when using initial='US' the select defaults to "American Samoa" because it is the first item in the list with the value of "+1", rather than "United States".

    Is there a way to set the initial value based on the label rather than the value because of the duplicate country codes?

    opened by nwaxiomatic 14
  • Save should not raise `ValueError` on invalid phonenumber

    Save should not raise `ValueError` on invalid phonenumber

    Save() should only raise ValueErrors when the data to be stored is incompatible with the raw field data. A string that contains data that is not a valid phone number doesn't count as invalid, and should be checked in clean(), not in save().

    closes #334

    opened by karolyi 14
  • Fix value when null is True

    Fix value when null is True

    opened by lucifurtun 12
  • Default Country Code?

    Default Country Code?

    Is there a way append a default country code? If no Country code is typed? I am thinking along the lines of, mobile = PhoneNumberField(required=True, country='india') or mobile = PhoneNumberField(required=True, country='+91') My users are not smart enough to add their own country code, sometimes. It raises few errors. I currently tell them add the country code in a html placeholder.

    opened by CT83 12
  • Add a new widget for smart switching between national and international formats

    Add a new widget for smart switching between national and international formats

    Currently, if using PHONENUMBER_DEFAULT_FORMAT = 'NATIONAL' numbers that are entered in international format lose their country information on loading the form, meaning they cannot be validated. This widget checks if the number provided is in the expected region and renders it in national format if so, or international if there's a mismatch.

    opened by MatthewWilkes 11
  • Fix #41

    Fix #41

    This seems to solve #41. Let me know if my understanding of how this should work is wrong.

    opened by jeffbowen 11
  • Add fix for national + international numbers combined

    Add fix for national + international numbers combined

    Another attempt at #331

    opened by fraimondo 11
  • Several improvements

    Several improvements

    I made several little tweaks to the field. There were a few subtle bugs introduced in recent commits, which should be fixed. I also gave the test suite some love. Two features were added; specificing PHONENUMBER_DEFAULT_FORMAT (instead of defaulting to E164), and hinting at the region when using parse_string.

    I've added a note on null=True being discouraged for usage with the PhoneNumberField. As with CharFields, in most cases one doesn't want two different "empty" statuses, '' and None.

    I suggest making PhoneNumberField stricter, only accepting valid phone numbers by default. But that's a backwards-incompatible change and should be discussed.

    opened by maikhoepfel 11
  • Serializer field raises TypeError instead of ValidationError

    Serializer field raises TypeError instead of ValidationError

    I noticed that when validating a phone number a TypeError is raised. Comparing this to the EmailField where a ValidationError is raised. I would expect also a ValidationError. Is this behaviour intended?

    from rest_framework import serializers
    from phonenumber_field.serializerfields import PhoneNumberField
    
    class EmailSerializer(serializers.Serializer):
        email = serializers.EmailField()
    
    s = EmailSerializer(data={'email': 0})
    print('Email valid:', s.is_valid())
    

    Output:

    Email valid: False

    from rest_framework import serializers
    from phonenumber_field.serializerfields import PhoneNumberField
    
    class PhoneSerializer(serializers.Serializer):
        phone = PhoneNumberField()
    
    s = PhoneSerializer(data={'phone': 0})
    print('Phone valid:', s.is_valid())
    

    Output:

    Traceback (most recent call last): File "/usr/lib/python3.9/code.py", line 90, in runcode exec(code, self.locals) File "", line 1, in File "/path/to/test_phonenumberfield.py", line 16, in print('Is phone valid:', s.is_valid()) File "/path/to/venv/lib/python3.9/site-packages/rest_framework/serializers.py", line 220, in is_valid self._validated_data = self.run_validation(self.initial_data) File "/path/to/venv/lib/python3.9/site-packages/rest_framework/serializers.py", line 419, in run_validation value = self.to_internal_value(data) File "/path/to/venv/lib/python3.9/site-packages/rest_framework/serializers.py", line 476, in to_internal_value validated_value = field.run_validation(primitive_value) File "/path/to/venv/lib/python3.9/site-packages/rest_framework/fields.py", line 799, in run_validation return super().run_validation(data) File "/path/to/venv/lib/python3.9/site-packages/rest_framework/fields.py", line 568, in run_validation value = self.to_internal_value(data) File "/path/to/venv/lib/python3.9/site-packages/phonenumber_field/serializerfields.py", line 12, in to_internal_value phone_number = to_python(data) File "/path/to/venv/lib/python3.9/site-packages/phonenumber_field/phonenumber.py", line 149, in to_python raise TypeError("Can't convert %s to PhoneNumber." % type(value).name) TypeError: Can't convert int to PhoneNumber.

    I found some related issue but none seems to cover this: #306, #225, #389, #265 Sorry if I missed the relevant discussion

    opened by videda 2
  • Object of type PhoneNumber is not JSON serializable when running manage.py dumpdata

    Object of type PhoneNumber is not JSON serializable when running manage.py dumpdata

    I have a custom user model with a PhoneNumber field as below:

    ` class CustomUser(AbstractBaseUser, PermissionsMixin):

    phone = PhoneNumberField(_('phone number'), unique=True)

    email = models.EmailField(_('email address'), max_length=254, unique=True, null=True, blank=True)
    
    full_name = models.CharField(_('full name'), max_length=254,
                                 help_text=_('The full name as it appears on ID or passport'))
    

    `

    When I want to export any model that is linked to my user model

    python manage.py dumpdata --natural-foreign --natural-primary --indent 2 users.customuser users.userprofile > testUsers.json

    It's failing with this error:

    CommandError: Unable to serialize database: Object of type PhoneNumber is not JSON serializable

    However when I run:

    python manage.py dumpdata --natural-foreign --natural-primary --indent 2 users.customuser > testUsers.json

    It's working just fine. The problem comes for models linked to my user model

    opened by scroogeT 3
  • form field clears when either country code or phone number text is empty

    form field clears when either country code or phone number text is empty

    For an edge case where user would have entered phone number text but not select country code, or selected the country code but not added the phone number, I am noticing that when the form is submitted, then due to if all(values): check in PhoneNumberPrefixWidget.value_from_datadict method, the rerendered form has user entries wiped out.

    I feel a better experience would be to leave the partial user data on form as-is. I am not sure if the criteria is even helping at all, and if it is better removed, i.e. simply return "%s.%s" % tuple(values) for all cases. Anyways, the to_python method in formfields.PhoneNumberField will raise a validation error (here)

    opened by KunjPrasad 0
  • Use separate attrs for select and text form field to help with accessibility

    Use separate attrs for select and text form field to help with accessibility

    I am using PhoneNumberPrefixWidget (link). I want to provide different widget attributes for phone country code select and phone number text fields. A primary goal is to provide different aria-label attributes for the two input type because I'm unable to identify how to put different label for each and position it side by side since it is a MultiWidget. Not sure if there are alternate ways to make it accessible.

    Looking at other example of MultiWidget in Django (like, here), it seems that different attrs kwargs are defined.

    opened by KunjPrasad 0
  • How do you limit the number of choices of the widget

    How do you limit the number of choices of the widget

    Is there a built-in setting to limit the number of choices to specific ones? Or do I need to override the select widget?

    opened by Superflyer11 0
  • Added zh-hant locale

    Added zh-hant locale

    opened by xflyer11 1
  • values_list() returns the non international format

    values_list() returns the non international format

    When trying to add a phone_number field to list using the values_list() it will return the phone_number field as a string in its non-international form even though I've added my settings:

    PHONENUMBER_DB_FORMAT = 'NATIONAL' PHONENUMBER_DEFAULT_REGION = 'SE'

    e.g 070 255 25 25 instead of +46 70 255 25 25, is this intentional? This is my DB query. users = CustomUser.objects.annotate(subscribed_city_list=ArrayAgg('subscribed_city__name')).values_list('subscribed_city_list', 'user_id', 'phone_number').order_by('user_id')

    This is what the data coming out looks like: <QuerySet [('[email protected]', ['vienna', 'stockholm'], UUID('0c9d04de-b28f-410f-8963-be24edd74070'), '070-255 25 25')]>

    Would be nice to have an explanation as to why, and what I might be able to do instead. I unfortunately can't change the query up for various reasons.

    opened by Tobeyforce 3
  • Problem to validate short business numbers

    Problem to validate short business numbers

    Hi,

    I just tried django-phonenumber-field in my project and it seems so good. but I have problem to enter short numbers specially 4 or 5 digit numbers that used to use for business call centers.

    Is there any settings that let me validate such numbers or it need a hack?

    opened by Ali-Javanmardi 1
  • KZ locale instead of RU

    KZ locale instead of RU

    when i select the Russian localization ( PHONENUMBER_DEFAULT_REGION = 'RU' in settings.py), Kazakhstan is displayed in the template

    bug 
    opened by repair-cat 6
  • Allow different region validation in DRF SerializerField from PHONENUMBER_DEFAULT_REGION

    Allow different region validation in DRF SerializerField from PHONENUMBER_DEFAULT_REGION

    Hi

    Currently in our app we don't use Django Forms, all data goes through serializers and so basing from The solution provided here

    Is it possible to declare the fields for a specific region validation?

    i.e. something like:

    class ASerializer(ModelSerializer):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            fields = getattr(self, "_fields", None)
            try:
                instance = args[0]
            except IndexError:
                instance = None
            if not instance:
               return
            if not hasattr(instance, 'get_country', None):
                return
            country = instance.get_country
            self._fields[field_name] = PhoneNumberField(region=country)
    

    I am trying this approach but currently getting

     File "xxx", line 274, in __init__
        self._fields[field_name] = PhoneNumberField(region=country)
      File "xxx/.pyenv/versions/3.6.11/envs/brokerengine/lib/python3.6/site-packages/rest_framework/fields.py", line 754, in __init__
        super(CharField, self).__init__(**kwargs)
    TypeError: __init__() got an unexpected keyword argument 'region'
    

    Looks like custom regions in DRF serializers are not supported yet? (I may have to write additonal code for that) By doing this will I be able to override the normal validation that happens for the default region?

    opened by jrbenriquez 0
Releases(6.0.0)
  • 6.0.0(Nov 10, 2021)

    What's Changed

    • Add support for Python 3.10
    • Update Czech, Dutch and pt_BR translations

    Backwards incompatible changes

    • formfields.PhoneNumberField with a region now display national phone numbers in the national format instead of PHONENUMBER_DEFAULT_FORMAT. International numbers are displayed in the PHONENUMBER_DEFAULT_FORMAT.

    New Contributors

    • @maartenkling made their first contribution in https://github.com/stefanfoulis/django-phonenumber-field/pull/449
    • @melanger made their first contribution in https://github.com/stefanfoulis/django-phonenumber-field/pull/454
    • @willunicamp made their first contribution in https://github.com/stefanfoulis/django-phonenumber-field/pull/456
    • @fraimondo made their first contribution in https://github.com/stefanfoulis/django-phonenumber-field/pull/469

    Full Changelog: https://github.com/stefanfoulis/django-phonenumber-field/compare/5.2.0...6.0.0

    Source code(tar.gz)
    Source code(zip)
Owner
Stefan Foulis
/me ❤️ [Python, Django, Docker]
Stefan Foulis
MAC address Model Field & Form Field for Django apps

django-macaddress MAC Address model and form fields for Django We use netaddr to parse and validate the MAC address. The tests aren't complete yet. Pa

null 45 Oct 19, 2021
Tweak the form field rendering in templates, not in python-level form definitions. CSS classes and HTML attributes can be altered.

django-widget-tweaks Tweak the form field rendering in templates, not in python-level form definitions. Altering CSS classes and HTML attributes is su

Jazzband 1.6k Nov 18, 2021
A reusable Django model field for storing ad-hoc JSON data

jsonfield jsonfield is a reusable model field that allows you to store validated JSON, automatically handling serialization to and from the database.

Ryan P Kilby 1.1k Nov 23, 2021
Twitter Bootstrap for Django Form - A simple Django template tag to work with Bootstrap

Twitter Bootstrap for Django Form - A simple Django template tag to work with Bootstrap

tzangms 558 Oct 21, 2021
Basic Form Web Development using Python, Django and CSS

thebookrain Basic Form Web Development using Python, Django and CSS This is a basic project that contains two forms - borrow and donate. The form data

Ananya Dhulipala 1 Nov 27, 2021
Custom Django field for using enumerations of named constants

django-enumfield Provides an enumeration Django model field (using IntegerField) with reusable enums and transition validation. Installation Currently

5 Monkeys 182 Oct 27, 2021
Location field and widget for Django. It supports Google Maps, OpenStreetMap and Mapbox

django-location-field Let users pick locations using a map widget and store its latitude and longitude. Stable version: django-location-field==2.1.0 D

Caio Ariede 460 Nov 27, 2021
A Django application that provides country choices for use with forms, flag icons static files, and a country field for models.

Django Countries A Django application that provides country choices for use with forms, flag icons static files, and a country field for models. Insta

Chris Beaven 1k Nov 24, 2021
A Django application that provides country choices for use with forms, flag icons static files, and a country field for models.

Django Countries A Django application that provides country choices for use with forms, flag icons static files, and a country field for models. Insta

Chris Beaven 1k Nov 24, 2021
A drop-in replacement for django's ImageField that provides a flexible, intuitive and easily-extensible interface for quickly creating new images from the one assigned to the field.

django-versatileimagefield A drop-in replacement for django's ImageField that provides a flexible, intuitive and easily-extensible interface for creat

Jonathan Ellenberger 470 Nov 26, 2021
A pickled object field for Django

django-picklefield About django-picklefield provides an implementation of a pickled object field. Such fields can contain any picklable objects. The i

Gintautas Miliauskas 151 Nov 27, 2021
A pickled object field for Django

django-picklefield About django-picklefield provides an implementation of a pickled object field. Such fields can contain any picklable objects. The i

Gintautas Miliauskas 150 Nov 15, 2021
This website serves as an online database (hosted via SQLLite) for fictional businesses in the area to store contact information (name, email, phone number, etc.) for fictional customers.

Django-Online-Business-Database-Project this project is still in progress Overview of Website This website serves as an online database (hosted via SQ

null 1 Oct 30, 2021
Twitter Bootstrap for Django Form

Django bootstrap form Twitter Bootstrap for Django Form. A simple Django template tag to work with Bootstrap Installation Install django-bootstrap-for

tzangms 558 Oct 21, 2021
This is a sample Django Form.

Sample FORM Installation guide Clone repository git clone https://github.com/Ritabratadas343/SampleForm.git cd to repository. Create a virtualenv by f

Ritabrata Das 1 Nov 5, 2021
Django URL Shortener is a Django app to to include URL Shortening feature in your Django Project

Django URL Shortener Django URL Shortener is a Django app to to include URL Shortening feature in your Django Project Install this package to your Dja

Rishav Sinha 4 Nov 18, 2021
django-reversion is an extension to the Django web framework that provides version control for model instances.

django-reversion django-reversion is an extension to the Django web framework that provides version control for model instances. Requirements Python 3

Dave Hall 2.7k Dec 2, 2021
Full control of form rendering in the templates.

django-floppyforms Full control of form rendering in the templates. Authors: Gregor Müllegger and many many contributors Original creator: Bruno Renié

Jazzband 793 Nov 8, 2021
Full control of form rendering in the templates.

django-floppyforms Full control of form rendering in the templates. Authors: Gregor Müllegger and many many contributors Original creator: Bruno Renié

Jazzband 793 Nov 8, 2021