pythonpython-3.xdjangodjango-formsdjango-validation

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


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?


Solution

  • 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