Sparrow SMS Phone Verification API in Django - Part 1

In this post, we're going to code in Python Django to use the Sparrow SMS API integration to verify a Nepali NTC/ Ncell phone number using an API as a service server-generated OTP code.

NOTE: This is Part 1 of a multi-part series.

Part 2 is coming next week.

In this post, we're going to know how to code modules in Python Django to use the Sparrow SMS API integration to verify a Nepali phone number (NTC/ Ncell) using an API as a service server-generated OTP code. This is an works in production example of an API as a service backend web app built around Django and Django REST framework that allows clients like mobile apps or React.js/ Vue.js enabled frontend interfaces to integrate a phone number verification using Sparrow SMS service gateway. In addition, this feature could be used as a sign in or sign up wall during user authentication.

To follow this post ahead, you will need:

Source: Google Developers Guides

Assumed we have installed the requirements and started running an instance of a Django main project successfully, we can start by creating a new Django app using:

$ python manage.py startapp myappname
Creating a Django App from Terminal

that will create a directory structure as:

myappname/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py
Default Django App Directory Listing

Sticking to the dev conventions, we will add more python files to the app later such as urls.py, serializers.py etc.

Step 1 — Defining database layout in models.py

The first step is to add some basic imports needed in our models.py file. MinLengthValidator and RegexValidator are the built-in validator classes from django.core module that checks the minimum length of a value and performs re.search() by a regex validation respectively. Next up we have models which is the most common and important db import. Finally the AbstractUser module allows us to customize the default user groups and auth permissions that comes battery included in django.contrib.

from django.db import models
from django.contrib.auth.models import AbstractUser
from django.core.validators import MinLengthValidator, RegexValidator
Imports in models.py
class AccountUser(AbstractUser):

# other very important account user fields here

phone_regex = RegexValidator(regex=r'^98\d{8}$', message="Only 10 digits NTC or NCELL numbers allowed.")
phone_number = models.CharField(validators=[phone_regex], max_length=10, null=True, unique=True)
phone_verified = models.BooleanField(default=False)
Phone model attributes inside AccountUser

Here AccountUser is a custom account user model class that entails custom user model attributes like username, first_name, last_name etc. The custom class AccountUser subclasses in-built AbstractUser from django.contrib.auth.models from the imports section above.

AbstractUser provides the full implementation of the default User as an abstract model. - Django 3.2
class PhoneOtp(models.Model):
    phone_regex = RegexValidator(regex=r'^98\d{8}$', message="Only 10 digits NTC or NCELL numbers allowed.")
    phone_number = models.CharField(validators=[phone_regex], max_length=10, null=True, unique=True)
    validated = models.BooleanField(default=False, help_text="Ensure Mobile Verified Badge")
    otp_code = models.CharField(max_length=6, blank=True, null=True)
    otp_count = models.PositiveSmallIntegerField(default=0, help_text='Count of OTP sent.')

    def __str__(self):
        return self.otp_code + ' is the otp for ' + self.phone_number
A parent class in models.py for phone numbers database

Next is the class PhoneOtp that has a custom regex validator starting in line 2. If you look closely the regex only allows phone numbers that start with 98 plus any 8 digits afterwards; a total of 10 digit phone number 9812345678. But there are phone numbers in Nepal that start with 97 too. So you just need to change the regex as per your needs on phone_regex line 2.

phone_number will hold the 10 digit phone number and validate against the phone_regex rules specified above it; added to it you have other arguments like max_length null and unique to meddle in the database properties.

max_length allows you to set a maximum length of phone number digits including white spaces.
null specifies whether the phone number is allowed to be saved as a void in the database or not.
unique specifies the phone number to be unique in the database once saved unless popped off.

validated is another important model attribute that will store a boolean value; either a True or a False. This is where we set the verification badge status after the users have successfully verified their phone numbers. Each phone number entry in the database are set False 0 by default until the user verifies the phone number in which case the entry is updated to True 1. And in turn, the frontend UI developers can code the appropriate to denote the phone number as verified, checked etc.

otp_code will hold the 6 digits randomly generated number by the generate_otp function in the views.py file which in turn will act as the 6 digits One Time Passwords sent to the user's phone numbers by the Sparrow SMS API gateway.

otp_count will hold the integer values of the number of times the OTP is sent to a phone number by the server. This data will be useful to limit the unwanted retries by users for OTP to request or overload the SMS gateway within API level access.

Activating our AccountUser and PhoneOtp models from Terminal.

python manage.py makemigrations myappname
Save changes in models.py
python manage.py migrate myappname
Apply saved changes in models.py

Step 2 — Registering patterns to urls.py

from django.urls import path
from .views import ValidatePhoneSendOTP, ValidateOTP


app_name = 'myappname'
urlpatterns = [
    path('', ValidatePhoneSendOTP.as_view()),
    path('verify/', ValidateOTP.as_view()),
]
Setting URL patterns

After writing the necessary database models and attributes for our phone database, we create a new urls.py file at the root of our Django app myappname.

Django doesn't have urls.py by default. Devs create it later as per needs. It helps us manage all routes, url paths and patterns of an app within a file.

Starting off imports, the most basic module to import is path that returns for urlpatterns. ValidatePhoneSendOTP and ValidateOTP are API view classes that subclass Django's View class. These will arrive later in Writing Final Views part of this article.

app_name is crucial to let Django know that urlpatterns we write below it should work with the app name specified.

Hence, line 7 sets '' root of the relative path to return ValidatePhoneSendOTP. And line 8 sets verify/ in the relative path to return ValidateOTP.

Django's URLconf Notes from Docs:

  • There’s no need to add a leading slash because every URL has that. For example, it’s articles, not /articles.
  • path matches any non-empty string, including the path separator, /.

💡
I edit and update this article timely. Thank you