Registration of django rest framework

I haven't updated many articles recently

It's really a little busy

I have been studying django rest framework, or drf for short

The development concept of drf conforms to the modern development concept

Front and rear split type

And I, Xiaobai, want to

Experience the process of front and back-end separated development

Although the leader of front-end and back-end separated development is java

But how can python join the fun

So I studied it

Because of the need for joint debugging, it is just a small function of registration

I've been debugging for about an hour, which is enough food-=-

No more nonsense, just go to the code

1. First look at our models

from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils import timezone


class UserProfile(AbstractUser):
    """
    user
    """
    nickname = models.CharField(max_length=20, null=True, blank=True, verbose_name="nickname")
    mobile = models.CharField(max_length=11, null=True, blank=True, verbose_name="mobile phone")
    email = models.CharField(max_length=125, null=True, blank=True, verbose_name="mailbox")
    introduction = models.TextField(blank=True, null=True, verbose_name='brief introduction', default='The user was lazy and didn't write anything...')
    avatar = models.ImageField(upload_to='users/avatars/', null=True, blank=True, verbose_name='head portrait', default='')
    address = models.CharField(max_length=100, null=True, blank=True, verbose_name='User address', default='')
    birthday = models.DateField(verbose_name='birthday', blank=True, null=True, default=timezone.now)

    class Meta:
        verbose_name = "user"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username

    def get_profile_name(self):
        if self.nickname:
            return self.nickname
        return self.username


class VerifyCode(models.Model):
    """
    SMS or email verification code
    """
    code = models.CharField(max_length=10, verbose_name="Verification Code", default='')
    account = models.CharField(max_length=125, verbose_name="account number", default='')
    account_type = models.CharField(verbose_name="account type", choices=(("email", "mailbox"), ("mobile", "mobile phone")),
                                    default='email', max_length=6)
    add_time = models.DateTimeField(default=timezone.now, verbose_name="Add time")

    class Meta:
        verbose_name = "Verification Code"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.code

One user model, one verification code model

2.views view layer

from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
from django.shortcuts import render

# Create your views here.

from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
from rest_framework import viewsets, mixins, status
from rest_framework_jwt.serializers import jwt_payload_handler,jwt_encode_handler

from .models import UserProfile
from .models import VerifyCode
from user.serializers import VerifySerializer, UserRegisterSerializer
from utils.utils import send_verify_code_by_email,generate_code

User=get_user_model()

···


class VerifyCodeViewset(mixins.CreateModelMixin,viewsets.GenericViewSet):
    """
    Send email or mobile verification code
    """
    serializer_class = VerifySerializer
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        account=serializer.validated_data['account']
        account_type=serializer.validated_data['account_type']
        verifycode=generate_code()
        if account_type =='email':
            send_status=send_verify_code_by_email(verifycode,[account,])
            if send_status:
                #self.perform_create(serializer)
                vcode=VerifyCode(code=verifycode,account=account,account_type=account_type)
                vcode.save()
                headers = self.get_success_headers(serializer.data)
                return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
            else:
                headers = self.get_success_headers(serializer.data)
                return Response(serializer.data, status=status.HTTP_400_BAD_REQUEST, headers=headers)
        else:
            pass



class UserRegisterViewset(mixins.CreateModelMixin,viewsets.GenericViewSet):
    """User registration"""
    serializer_class = UserRegisterSerializer

    def create(self, request, *args, **kwargs):
        serializer=self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user=self.perform_create(serializer)
        ret_data=serializer.data
        headers=self.get_success_headers(serializer.data)
        payload=jwt_payload_handler(user)
        token=jwt_encode_handler(payload)
        additional_data={'nickname':user.nickname,'userid':user.id,'token':token}
        ret_data.update(additional_data)
        return Response(ret_data,status=status.HTTP_201_CREATED,headers=headers)

    def perform_create(self, serializer):
        return serializer.save()

I don't think the code here is difficult to understand

It's mainly about this

serializer_class=

This sentence of code is to name the class to be serialized with

Of course, the class name behind this is self generated

Then write the code of the class

So I think this is the most important thing

Of course, the above two codes are simple create methods

3. Serialization class

from datetime import datetime,timedelta
import re

from django.contrib.auth import get_user_model
from django.contrib.auth.hashers import make_password
from django.db.models import Q
from rest_framework import serializers

from user.models import UserProfile,VerifyCode
from .models import UserProfile
User=get_user_model()

···

#Mobile number regular expression
REGEX_MOBILE="^1[358]\d{9}$|^147\d{8}$|^176\d{8}$"

class VerifySerializer(serializers.ModelSerializer):
    account_type=serializers.ChoiceField(choices=(("email","mailbox"),("mobile","mobile phone")),help_text='account type')
    account=serializers.CharField(max_length=125,help_text="account number")

    # def validate_account(self, account):
    #     print(account)
    def validate(self, attrs):
        accountType=attrs['account_type']
        account=attrs['account']
        #Judge whether the account is registered
        if User.objects.filter(Q(mobile=account)|Q(email=account)).first():
            raise serializers.ValidationError("User already exists")
        if accountType=='mobile':
            #Verify whether the mobile phone number is legal
            if not re.match(REGEX_MOBILE,account):
                raise serializers.ValidationError("Illegal mobile phone number")

        return attrs

    class Meta:
        model=VerifyCode
        fields=['account','account_type']

class UserRegisterSerializer(serializers.ModelSerializer):
    account = serializers.CharField(required=True,write_only=True,max_length=125, help_text="account number")
    account_type = serializers.ChoiceField(required=True,write_only=True,choices=(("email", "mailbox"), ("mobile", "mobile phone")), help_text='account type')
    code=serializers.CharField(required=True,write_only=True,max_length=4,min_length=4,label="Verification Code",
                               error_messages={'blank':'Please enter the verification code','required':'Verification code is required'})

    """User registered serialization class"""
    def validate_code(self,code):
        account=self.initial_data['account']
        account_type=self.initial_data['account_type']
        existed=VerifyCode.objects.filter(account_type=account_type,account=account).order_by('-add_time')
        if existed:
            last_record=existed[0]
            five_mintes_ago=datetime.now()-timedelta(hours=0,minutes=5,seconds=0)
            if last_record.code!=code:
                raise serializers.ValidationError("sorry:( Verification code error")
            if five_mintes_ago>last_record.add_time:
                raise serializers.ValidationError("sorry:( Verification code expired")

        else:
            raise serializers.ValidationError("sorry:( Verification code does not exist")

    def validate(self, attrs):
        accountType=attrs['account_type']
        if accountType=='email':
            attrs['email']=attrs['account']
        if accountType=='mobile':
            attrs['mobile']=attrs['account']
        attrs['nickname']=attrs['username']
        attrs['password']=make_password(attrs['password'])
        del attrs['code']
        del attrs['account_type']
        del attrs['account']
        return attrs

    class Meta:
        model=UserProfile
        fields=['username','account','account_type','code','password']

ok, the above is the code of the most important serialization class

Let me make a few comments

among

VerifySerializer

Is a serialized class that sends verification codes

The function is to obtain the verification code. You can choose whether to register by email or mobile phone

Then get the corresponding verification code

I took a look at the price of the mobile phone verification code

I couldn't help but cry

It costs four cents a piece

It's still a goose farm. Hey, it's not equipped with mobile phone registration for the time being

But we haven't studied the registration of mobile verification code yet

The second class,

UserRegisterSerializer

This is the complete registration class

The verification information is legal, then the verification code is sent, and then check whether the verification code is expired or invalid

wait

One of the most important things to talk about by name is this small parameter

write_only=True

You can find it in the code

Let me talk about the function directly. If this code is added, the attributes of the model in which this code is located will not be serialized by drf, and thus the corresponding objects will not be generated

Maybe you're a little dizzy. Let me explain this. In 1, we don't have the attribute of account in our user model, that is, UserProfile. However, when we send the verification code when registering, we must need the attribute of account, because the system can only send you the verification code when we know your account, whether it's phone or email

However, when serializing and generating UserProfile, we do not need the attribute account

Right

So we need to add

write_only=True

In this way, the front end also has an account, and the back end can also send verification codes

It can also avoid 500

Because when I didn't add it, the browser reported an error of 500

Later, I studied it according to the error information

It's its pot

It's her, it's her, our little Nezha!

Finally, put a picture of the front end

The front end uses vue+iview

The project is almost finished, and the rest is to publish blogs and personal centers

Why should I write this article today? Because it's really hard to register-=-

Especially the JWT with the front and rear ends separated

so,I finally figure it out

Then good night

Let's use another expression bag from the previous article

Posted by discombobulator on Fri, 15 Apr 2022 17:52:57 +0930