What's the best way to store a phone number in Django models?

DjangoDjango FormsDjango Validation

Django Problem Overview


I am storing a phone number in model like this:

phone_number = models.CharField(max_length=12)

The user would enter a phone number and I would use the phone number for SMS authentication. This application would be used globally. So I would also need a country code. Is CharField a good way to store a phone number? And, how do I validate the phone number?

Django Solutions


Solution 1 - Django

You might actually look into the internationally standardized format E.164, recommended by Twilio for example (who have a service and an API for sending SMS or phone-calls via REST requests).

This is likely to be the most universal way to store phone numbers, in particular if you have international numbers work with.

  1. Phone by PhoneNumberField

    You can use the phonenumber_field library. It is a port of Google's libphonenumber library, which powers Android's phone number handling. See django-phonenumber-field.

    In the model:

    from phonenumber_field.modelfields import PhoneNumberField
    
    class Client(models.Model, Importable):
        phone = PhoneNumberField(null=False, blank=False, unique=True)
    

    In the form:

    from phonenumber_field.formfields import PhoneNumberField
    class ClientForm(forms.Form):
        phone = PhoneNumberField()
    

    Get the phone as a string from an object field:

    client.phone.as_e164
    

    Normalize the phone string (for tests and other staff):

    from phonenumber_field.phonenumber import PhoneNumber
    phone = PhoneNumber.from_string(phone_number=raw_phone, region='RU').as_e164
    
  2. Phone by regexp

    One note for your model: E.164 numbers have a maximum character length of 15.

    To validate, you can employ some combination of formatting and then attempting to contact the number immediately to verify.

    I believe I used something like the following in my django project:

     class ReceiverForm(forms.ModelForm):
         phone_number = forms.RegexField(regex=r'^\+?1?\d{9,15}$',
                                         error_message = ("Phone number must be entered in the format: '+999999999'. Up to 15 digits is allowed."))
    

As per jpotter6, you can do something like the following in your models as well:

File models.py:

from django.core.validators import RegexValidator

class PhoneModel(models.Model):
    ...
    phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
    phone_number = models.CharField(validators=[phone_regex], max_length=17, blank=True) # Validators should be a list

Solution 2 - Django

Use django-phonenumber-field:

pip install django-phonenumber-field

Solution 3 - Django

Use a CharField for the phone field in the model and the localflavor app for form validation:

https://docs.djangoproject.com/en/1.7/topics/localflavor/

As of 2021-12-07, it looks like LocalFlavor is no longer part of Django.

Solution 4 - Django

This solution worked for me:

First install django-phone-field. Command:

pip install django-phone-field

Then in file models.py:

from phone_field import PhoneField
...

class Client(models.Model):
    ...
    phone_number = PhoneField(blank=True, help_text='Contact phone number')

And in file settings.py:

INSTALLED_APPS = [...,
                  'phone_field'
]

It looks like this in the end:

Phone in form

Solution 5 - Django

Validation is easy. Text them a little code to type in.

A CharField is a great way to store it. I wouldn't worry too much about canonicalizing phone numbers.

Solution 6 - Django

It all depends on what you understand as a phone number. Phone numbers are country-specific. The localflavors packages for several countries contains their own "phone number field". So if you are OK being country-specific you should take a look at localflavor package (class us.models.PhoneNumberField for the US case, etc.)

Otherwise you could inspect the localflavors to get the maximum length for all countries. Localflavor also has forms fields you could use in conjunction with the country code to validate the phone number.

Solution 7 - Django

I will describe what I use:

Validation: The string contains more than 5 digits.

Cleaning: removing all non-digit symbols and writing only numbers to the database. I'm lucky, because in my country (Russia) everybody has phone numbers with 10 digits. So I store only 10 digits in the database. If you are writing a multi-country application, then you should make a comprehensive validation.

Rendering: I write a custom template tag to render nicely it in the template. Or even render it like a picture - it is safer to prevent SMS spam.

Solution 8 - Django

Others mentioned django-phonenumber-field. To get the display format how you want you need to set PHONENUMBER_DEFAULT_FORMAT setting to "E164", "INTERNATIONAL", "NATIONAL", or "RFC3966", however you want it displayed. See the GitHub source.

Solution 9 - Django

First of all, you need to install the phone number Django package.

pip install django-phonenumber-field[phonenumbers]

Then next is to add it to the installed applications:

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

This is how to use it in your model:

from phonenumber_field.modelfields import PhoneNumberField

class Artist(models.Model):

    phone_number = PhoneNumberField()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionpynoviceView Question on Stackoverflow
Solution 1 - DjangoerewokView Answer on Stackoverflow
Solution 2 - DjangorgenitoView Answer on Stackoverflow
Solution 3 - DjangonicorelliusView Answer on Stackoverflow
Solution 4 - DjangoVMMFView Answer on Stackoverflow
Solution 5 - DjangoU2EF1View Answer on Stackoverflow
Solution 6 - DjangoesauroView Answer on Stackoverflow
Solution 7 - DjangoПавел ТявинView Answer on Stackoverflow
Solution 8 - DjangoGoPackGo90View Answer on Stackoverflow
Solution 9 - DjangoCynthia BensonView Answer on Stackoverflow