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

Part 3 is here.

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 Step 5: Writing Final Views part in this tutorial.

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, /.

Step 3 - Customize django-admin using admin.py

django-admin is a command-line utility package with an admin dashboard that comes battery included in the Django framework. Here we use @ to use the register decorator to register our AccountUserAdmin class and customize with ModelAdmin options.

from django.contrib import admin
from .models import AccountUser, PhoneOtp

@admin.register(AccountUser)
class AccountUserAdmin(admin.ModelAdmin):
    search_fields = ('username', 'email', 'first_name', 'last_name',)
    list_filter = ('user_type', 'is_staff', 'is_superuser', 'is_active')
    list_display = ('username', 'email', 'first_name', 'last_name', 'is_active', 'phone_verified', 'phone_number', 'user_type')

admin.site.register(PhoneOtp)
admin.py
  • search_fields enables a search box on the user list page.
  • list_filter enables a filter function in the right sidebar of the page.
  • list_display allows you to choose the attributes from the database to display on the admin site. Specifically, we've included phone_verified and phone_number to display on our admin site. So this would allow webmasters to see database entries directly updated in the UI of the admin site.

Step 4 - Render using serializers.py

from rest_framework.serializers import ModelSerializer, SerializerMethodField
from django.contrib.auth import get_user_model

UserModel = get_user_model()

class UserDetails(ModelSerializer):
    email_verified = SerializerMethodField(read_only=True)

    class Meta:
        model = UserModel
        fields = ('pk', 'is_active', 'profile_pic', 'user_type', 'email_verified', 'phone_verified', 'username', 'email', 'phone_number', 'first_name', 'last_name', 'date_joined',)
        read_only_fields = ('is_active', 'user_type', 'phone_verified', 'email', 'date_joined',)

    def get_email_verified(self, instance):
        return instance.emailaddress_set.get(user=instance).verified
serializers.py
Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON, XML or other content types.

The serializers in REST framework work very similarly to Django's Form and ModelForm classes. - Django REST framework

All we are trying to do is serialize the contents of the imported get_user_model() and activate a function that sets and returns the instance of the email address of the user as verified.

email_verified is set to read-only so that the integrity and verification are preserved well and true to unauthorized changes from outside the system.

I edit and update this article timely for corrections and improvements. Thank you for reading!