This article is participating in “Python Theme Month”. Check out Python Authoring season to show off your Python articles – $2000 limited prize waiting for you to win
Gitee address 👉 saas This tutorial corresponds to the code for [registration verification code processing] submission, can be viewed through the corresponding branch
User Registration
First, the overall mind map is as follows:
1. Prepare
1.1 Tencent Cloud sends SMS
- The login and registration function of the project needs to use the mobile phone number to receive SMS messages. Tencent cloud SMS is used here
- Tencent Cloud short Message Service (SMS) using Python
1.2 redis
- Redis can be downloaded, installed and operated by Python, and django can be connected to Redis
2. Display the registration page
2.1 create app
- Create a file named
web
The following code is written in this apppython manage.py startapp web Copy the code
2.2 the app to register
settings.py
Register app in file,INSTALLED_APPS
Add the app you just createdINSTALLED_APPS = [ 'django.contrib.admin'.'django.contrib.auth'.'django.contrib.contenttypes'.'django.contrib.sessions'.'django.contrib.messages'.'django.contrib.staticfiles'.'app01.apps.App01Config'.'web.apps.WebConfig',]Copy the code
2.3 Master preparation
2.3.1 Plug-in introduction
- Before creating the master version, we need to introduce plug-ins such as Bootstrap and JS, which can be used by CDN or downloaded for offline use. Here we download them and place them in the
static
Folder, so we can use it later
Can go to their website to download the offline files, can also take I have downloaded good here, I put it in the cloud, the need for download, including: js, the bootstrap, the font – awesome links: icon 】 【 pan.baidu.com/s/1gQRN57Xg…
Extraction code: MNJL Decompression password: ruochen666
- in
web
Next create a static file storestatic
Folder and then create another oneplugin
The bootstrap folder is used to store the tool class files, and then place the downloaded JS, bootstrap, and font-awesome into thestatic
In the folder, the structure is shown as follows
- And then we can introduce it directly when we’re going to use it
static
Files under the folder
2.3.2 stamper
Why use master? In the front-end page, the registration and login pages are basically similar, so we can make these two pages inherit from the master version to achieve code reuse
- in
web
So let’s create onetemplates
Folder, intemplates
Create another one under the folderlayout
Folder for our master filesbasic.html
- Structure is as follows
- 'basic.html' code is as follows, The style of the navigation bar directly from [the bootstrap website components] over here (https://v3.bootcss.com/components/#navbar) can be modified ` ` ` HTML {% load static %} <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %}</title> <link rel="stylesheet" href="{% static '/plugin/bootstrap/css/bootstrap.min.css' %}"> <link rel="stylesheet" href="{% static '/plugin/font-awesome/css/font-awesome.min.css' %}"> <style> .navbar-default{ border-radius: 0; } </style> {% block css %}{% endblock %} </head> <body> <nav class="navbar navbar-default"> <div class="container"> <! -- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Tracer</a> </div> <! -- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul Class = "nav navbar - nav" > < li > < a href = "#" > product features < / a > < / li > < li > < a href = "#" > enterprise solutions < / a > < / li > < li > < a href = "#" > help document < / a > < / li > < li > < a Price href = "#" > < / a > < / li > < / ul > < ul class = "nav navbar - nav navbar - right" > < li > < a href = "#" > Link < / a > < / li > < li class = "dropdown can" > <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> </ul> </li> </ul> </div> </div> </nav> {% {% endblock %} <script SRC ="{% static 'js/jquery-3.4.1.min.js' %}"></script> <script SRC ="{% static 'plugin/bootstrap/css/bootstrap.min.css' %}"></script> {% block js %}{% endblock %} </body> </html> ```Copy the code
2.4 the URL to
MyDjango/MyDjango/urls.py
The name of my project isMyDjango
】"""MyDjango URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.11/topics/http/urls/ Examples: the Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url, include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^/', include('web.urls')),]Copy the code
- Create it in the Web folder
urls.py
File to manage the route of the app (view function we’ll write below)# -*- coding: UTF-8 -*- "' = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = @ Project - > File: MyDjango - > urls @ IDE: PyCharm @ the Author: Ruochen @ Date: 2020/7/2 1:18 @ Desc: = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ' ' ' from django.conf.urls import url from web.views import account urlpatterns = [ url(r'^register/$', account.register, name='register'), # register ] Copy the code
2.5 Model Preparation [Models.py]
- User registration, to fill in the data are
- The user name
- Mobile phone no.
- password
- in
web/models.py
Create one in the fileUserInfo
Class, code as followsfrom django.db import models class UserInfo(models.Model) : username = models.CharField(verbose_name='Username', max_length=32) email = models.EmailField(verbose_name='email', max_length=32) mobile_phone = models.CharField(verbose_name='Mobile phone Number', max_length=32) password = models.CharField(verbose_name='password', max_length=32) def __str__(self) : return self.username Copy the code
- Migrating a Database
python manage.py makemigrations python manage.py migrate Copy the code
2.5 View Functions
- Under the web
views.py
Delete file, create oneviews
Folders for easy management of our view and then inviews
Create one under the folderaccount.py
The file acts as a registered view with the following code 🙁RegisterModelForm
andregister.html
It will be later)from django.shortcuts import render from web.forms.account import RegisterModelForm def register(request) : form = RegisterModelForm() return render(request, 'register.html', {'form': form}) Copy the code
2.6 ModelForm [Simple Validation & Style Addition]
- The front end of the page will loop through the Form to generate the data, but it is a bit ugly to generate the data directly, and the data will need to do some basic verification.
- in
web
Create one under the folderforms
Folder,forms
Create in folderaccount.py
File, code as follows- 1: Fields are processed, for example, the mobile phone number is verified and the password is
PasswordInput
Form etc. - Two: add to each field
form-control
Style, front-end page display is a little more beautiful - 3: add
code
Verification code field
# -*- coding: UTF-8 -*- "' = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = @ Project - > File: MyDjango - > account @ IDE: PyCharm @ the Author: Ruochen @ Date: 2020/7/2 children @ Desc: = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ' ' ' from django import forms from django.core.validators import RegexValidator from web import models class RegisterModelForm(forms.ModelForm) : mobile_phone = forms.CharField( label='Mobile phone Number', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$'.'Mobile phone number format error'), ]) password = forms.CharField( label='password', widget=forms.PasswordInput()) confirm_password = forms.CharField( label='Double password', widget=forms.PasswordInput()) code = forms.CharField( label='Captcha', widget=forms.TextInput()) class Meta: model = models.UserInfo fields = ['username'.'email'.'password'.'confirm_password'.'mobile_phone'.'code'] def __init__(self, *args, **kwargs) : super().__init__(*args, **kwargs) for name, field in self.fields.items(): field.widget.attrs['class'] = 'form-control' field.widget.attrs['placeholder'] = 'Please enter {}'.format(field.label,) Copy the code
- 1: Fields are processed, for example, the mobile phone number is verified and the password is
- There is no problem with using the above code, however, for adding
form-control
We can wrap it in a class so that when we need to add styles, we can just inherit from that class. - Modify as follows, in
web/forms
So let’s create onebootstrap.py
File with the following code:# -*- coding: UTF-8 -*- "' = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = @ Project - > File: MyDjango - > the bootstrap @ IDE: PyCharm @ the Author: Ruochen @ Date: 2020/7/3 16:25 @ Desc: = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ' ' ' class BootStrapForm(object) : bootstrap_class_exclude = [] def __init__(self, *args, **kwargs) : super().__init__(*args, **kwargs) for name, field in self.fields.items(): if name in self.bootstrap_class_exclude: continue old_class = field.widget.attrs.get('class'.' ') field.widget.attrs['class'] = '{} form-control'.format(old_class) field.widget.attrs['placeholder'] = 'Please enter {}'.format(field.label,) Copy the code
- then
forms/account.py
Modify the file tofrom django import forms from django.core.validators import RegexValidator from web import models from web.forms.bootstrap import BootStrapForm class RegisterModelForm(BootStrapForm, forms.ModelForm) : password = forms.CharField( label='password', min_length=8, max_length=64, error_messages={ 'min_length': "Password length should not be less than 8 characters.".'max_length': "Password length cannot exceed 64 characters." }, widget=forms.PasswordInput()) confirm_password = forms.CharField( label='Double password', min_length=8, max_length=64, error_messages={ 'min_length': "Repeat password must be at least 8 characters long.".'max_length': "Repeat password length cannot exceed 64 characters." }, widget=forms.PasswordInput() ) mobile_phone = forms.CharField( label='Mobile phone Number', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$'.'Mobile phone number format error'), ]) code = forms.CharField( label='Captcha', widget=forms.TextInput()) class Meta: model = models.UserInfo fields = ['username'.'email'.'password'.'confirm_password'.'mobile_phone'.'code'] Copy the code
2.7 Front-end Page
- in
templates
Create a folderregister.html
Folder that inherits frombasic.html
- Front-end page for the display of fields, a direct circular display
form
The data generated by the form will do{% extends' Layout /basic.html' %} {% load static %} {% block title %} {% block CSS %}<link rel="stylesheet" href="{% static 'css/account.css' %}"> {% endblock %} {% block content %} <div class="account"> <div class="title">User registration</div> <form id="form" method="post" novalidate> {% csrf_token %} {% for field in form %} {% if field.name == 'code' %} <div class="form-group"> <label for="{{ field.id_for_label }}">{{ field.label }}</label> <div class="row"> <div class="col-xs-7"> {{ field }} <span class="error-msg">{{ field.errors.0 }}</span> </div> <div class="col-xs-5"> <input id="smsBtn" type="button" class="btn btn-default" value="Click to get the verification code"/> </div> </div> </div> {% else %} <div class="form-group"> <label for="{{ field.id_for_label }}">{{ field.lable }}</label> {{ field }} <span class="error-msg">{{ field.errors.0 }}</span> </div> {% endif %} {% endfor %} <div class="row"> <div class="col-xs-3"> <input id="submit" type="button" class="btn btn-primary" value="-"/> </div> </div> </form> </div> {% endblock %} {% block js %} {% endblock %} Copy the code
3. Obtain the verification code
3.1 train of thought
- The button to obtain the verification code is bound with an event. In the front page, after the user clicks to obtain the verification code, the verification code is sent to the user’s mobile phone number through Tencent cloud SMS, and the 60s countdown is displayed on the page, and ajax requests are sent to the back end
- Verify the mobile phone number (to determine whether the mobile phone number has been registered) and verify the SMS template (some credentials of Tencent cloud SMS).
3.2 Specific Implementation
3.2.1 Front-end Code
- in
register.html
Add the js code as follows{% extends' Layout /basic.html' %} {% load static %} {% block title %} {% block CSS %}<link rel="stylesheet" href="{% static 'css/account.css' %}"> <style> .error-msg { color: red; position: absolute; font-size: 13px; } </style> {% endblock %} {% block content %} <div class="account"> <div class="title">User registration</div> <form id="form" method="POST" novalidate> {% csrf_token %} {% for field in form %} {% if field.name == 'code' %} <div class="form-group"> <label for="{{ field.id_for_label }}">{{ field.label }}</label> <div class="row"> <div class="col-xs-7"> {{ field }} <span class="error-msg"></span> </div> <div class="col-xs-5"> <input id="btnSms" type="button" class="btn btn-default" value="Click to get the verification code"> </div> </div> </div> {% else %} <div class="form-group"> <label for="{{ field.id_for_label }}">{{ field.label }}</label> {{ field }} <span class="error-msg"></span> </div> {% endif %} {% endfor %} <div class="row"> <div class="col-xs-3"> <input id="submit" type="button" class="btn btn-primary" value="-"/> </div> </div> </form> </div> {% endblock %} {% block js %} <script> // The function is automatically executed after the page frame is loaded $(function () { bindClickBtnSms(); }); /* Click the button binding event */ to get the captcha function bindClickBtnSms() {$('#btnSms').click(function () {$('.error-msg').empty(); // Get the phone number entered by the user // Find the ID of the input box, obtain the value according to the ID, how to find the mobile phone ID? // Django ModelForm generates fields with id_ + field names by default. var mobilePhone = $('#id_mobile_phone').val(); // Send the Ajax request, and send the mobile phone number $.ajax({ url: "{% url 'send_sms' %}".// Equivalent to /send/ SMS / type: "GET".data: {mobile_phone: mobilePhone, tpl: "register"}, // Mobile phone number and registration template dataType: "JSON".// Deserialize the data returned by the server into a dictionary success: function (res) { // The function that is automatically executed after the Ajax request is successfully sent: res is the value returned by the back end if(res.status) { sendSmsRemind(); } else { // Error message // console.log(res); // {status: False, error: {mobile_phone: [" error ",]} $.each(res.error, function (key, value) {$("#id_" + key).next().text(value[0]); })}})})}/* Countdown */ function sendSmsRemind() { var $smsBtn = $('#btnSms'); // Make the button unclickable $smsBtn.prop('disabled'.true); var time = 60; var remind = setInterval(function () { $smsBtn.val(time + 'Resend in seconds'); time = time - 1; if (time < 1) { clearInterval(remind); $smsBtn.val('Click on the captcha code').prop('disabled'.false); }},1000)}</script> {% endblock %} Copy the code
The 60s countdown on the front page uses the timer function, as follows
var obj = setInterval(function(){ // Create a timer, which is equivalent to executing function every second console.log(123); }, 1000) clearInterval(obj); // Turn off the timer Copy the code
Then, for the countdown function of 60s, we can use the following code to achieve it
var time = 60; var obj = setInterval(function(){ time = time - 1; if(time < 1) { clearInterval(obj); }},1000) Copy the code
- One of the
account.css
I wrote my own CSS style inweb/static
Create a new folder under this foldercss
The folder is used to store your own CSS styles, and then create a new oneaccount.css
File, code as follows.account { width: 400px; margin-top: 30px; margin-left: auto; margin-right: auto; border: 1px solid #f0f0f0; padding: 10px 30px 30px 30px; -webkit-box-shadow: 5px 10px 10px rgba(0.0.0.05); box-shadow: 5px 10px 10px rgba(0.0.0.05); } .account .title { font-size: 25px; font-weight: bold; text-align: center; } .account .form-group { margin-bottom: 20px; } Copy the code
3.2.2 Back-end code
3.2.2.1 URL
- First, it writes that the front end page sends an Ajax request to the back end via JS at the address
/send/sms/
, so we need to add one firsturl
.web/urls.py
The code is as follows:from django.conf.urls import url from web.views import account urlpatterns = [ url(r'^register/$', account.register, name='register'), # register url(r'^send/sms/$', account.send_sms, name='send_sms'), # register ] Copy the code
3.2.2.2 View Functions
- The route is added above, and the view function is added below
web/views/account.py
Add the code to the file as followsfrom django.shortcuts import render, HttpResponse from django.http import JsonResponse from web.forms.account import RegisterModelForm, SendSmsForm def register(request) : "" "register "" " form = RegisterModelForm() return render(request, 'register.html', {'form': form}) def send_sms(request) : """ Send a text message """ form = SendSmsForm(request, data=request.GET) # Only verify the phone number: cannot be blank, format is correct if form.is_valid(): return JsonResponse({'status': True}) return JsonResponse({'status': False.'error': form.errors}) Copy the code
3.2.2.3 Configuration File
3.2.2.3.1 Tencent Cloud SMS configuration file
- For Tencent cloud SMS profile, we should place it in
local_settings.py
File (local_settings.py
The role of files, which I mentioned in the last article, is also insettings.py
Declaration in the file local_settings.py
The file configuration code is as follows
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# --------- sms -----------
# Tencent cloud SMS app app_id
TENCENT_SMS_APP_ID = 'Own app_id'
# Tencent cloud SMS app app_key
TENCENT_SMS_APP_KEY = 'Own app_key'
# Tencent cloud SMS signature content
TENCENT_SMS_SIGN = 'xxxx'
# SMS template
TENCENT_SMS_TEMPLATE = {
'register': 'xxxx'.'login': 'xxxx',}Copy the code
For details about Tencent cloud SMS configuration, see this article: Python to operate Tencent cloud SMS (SMS) detailed tutorial
- App_id & app_key is the AppID & AppKey after the application is created
- SMS signature content is the content displayed after creating the signature, such as mine
Little ape like dust
As shown in the following
- The ID of an SMS template is the ID of an SMS template
settings.py
The document should also state the following (settings.py
Add the following code at the end of the file, assign whatever you want, because we imported it at the endlocal_settings.py
Files, projects actually uselocal_settings.py
Configuration in the file, just for the record, because ourlocal_settings.py
The documents are not to be given.)
# --------- sms -----------
# Tencent cloud SMS app app_id
TENCENT_SMS_APP_ID = 6666
# Tencent cloud SMS app app_key
TENCENT_SMS_APP_KEY = '6666'
# Tencent cloud SMS signature content
TENCENT_SMS_SIGN = 'xxxx'
# SMS template
TENCENT_SMS_TEMPLATE = {
'register': 666666.'login': 666666,}Copy the code
3.2.2.3.2 Redis configuration file
- See this article for details on redis:Redis download install & Python operation Redis & Django connect to RedisThat’s what’s used here
django-redis
Module [Remember to install] - The redis configuration is placed in
local_settings.py
In the file, the code is as follows:CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache"."LOCATION": "Redis: / / 192.168.1.6:6379".Run the [ipconfig] command on the terminal "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient"."CONNECTION_POOL_KWARGS": { "max_connections": 1000."encoding": 'utf-8' }, "PASSWORD": "root" # Password, as specified in the above article}}Copy the code
3.2.2.4 SendSmsForm
- In the view function above we pass
SendSmsForm
I checked it,web/forms/account.py
The code in the file is as follows- 1. Check the mobile phone number and SMS template
- Two: use Tencent cloud SMS to send short messages to users
- Create it in the project directory
utils
Folder to hold our utility class, and create another onetencent
Folder, created under the foldersms.py
File, as follows:
sms.py
The file code is as follows# -*- coding: UTF-8 -*- "' = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = @ Project - > File: MyDjango - > SMS @ IDE: PyCharm @ the Author: Ruochen @ Date: 2020/6/21 15:57 @ Desc: = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ' ' ' import ssl # ssl._create_default_https_context = ssl._create_unverified_context from qcloudsms_py import SmsMultiSender, SmsSingleSender from qcloudsms_py.httpclient import HTTPError from django.conf import settings def send_sms_single(phone_num, template_id, template_param_list) : """ Send a single SMS message :param phone_num: mobile phone number :param template_id: Tencent cloud SMS template ID :param template_param_list: Parameters required by the SMS template, for example, [Verification code: {1}, Description: {2}], pass [888,666] to format the template in sequence :return: "" appid = settings.TENCENT_SMS_APP_ID # apply ID to yourself appkey = settings.TENCENT_SMS_APP_KEY # Apply the Key yourself sms_sign = settings.TENCENT_SMS_SIGN # Signature content filled in when creating a signature on Tencent Cloud (if using an official account, this value is generally the full name or abbreviation of the official account) sender = SmsSingleSender(appid, appkey) try: response = sender.send_with_param(86, phone_num, template_id, template_param_list, sign=sms_sign) except HTTPError as e: response = {'result': 1000.'errmsg': "Network error sending failed"} return response def send_sms_multi(phone_num_list, template_id, param_list) : "" batch sending SMS messages :param phone_num_list: mobile phone number list: param template_id: Tencent cloud SMS template ID :param param_list: list of parameters required by the SMS template, for example: [Verification code: {1}, description: {2}], then pass [888,666] to format the template in order :return: """ appid = settings.TENCENT_SMS_APP_ID # apply ID to yourself appkey = settings.TENCENT_SMS_APP_KEY # Apply the Key yourself sms_sign = settings.TENCENT_SMS_SIGN # Signature content filled in when creating a signature on Tencent Cloud (if using an official account, this value is generally the full name or abbreviation of the official account) sender = SmsMultiSender(appid, appkey) try: response = sender.send_with_param(86, phone_num_list, template_id, param_list, sign=sms_sign) except HTTPError as e: response = {'result': 1000.'errmsg': "Network error sending failed"} return response Copy the code
- Create it in the project directory
- Third, the verification code is stored in redis database, and the timeout time is 60s [that is, it will disappear automatically after 60s], so that when we submit the form, we can compare the verification code entered by the user with that saved in Redis, and if the time exceeds 60s, the user has to obtain the verification code again
- You can see how Redis works in this article: Redis download install & Python operation Redis & Django connect to Redis
#-*- coding: UTF-8 -*- "' = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = @ Project - > File: MyDjango - > account @ IDE: PyCharm @ the Author: Ruochen @ Date: 2020/7/2 children @ Desc: = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ' ' ' import random from django import forms from django.core.validators import RegexValidator from django.core.exceptions import ValidationError from django.conf import settings from django_redis import get_redis_connection from web import models from web.forms.bootstrap import BootStrapForm from utils.tencent.sms import send_sms_single class RegisterModelForm(BootStrapForm, forms.ModelForm) : password = forms.CharField( label='password', min_length=8, max_length=64, error_messages={ 'min_length': "Password length should not be less than 8 characters.".'max_length': "Password length cannot exceed 64 characters." }, widget=forms.PasswordInput()) confirm_password = forms.CharField( label='Double password', min_length=8, max_length=64, error_messages={ 'min_length': "Repeat password must be at least 8 characters long.".'max_length': "Repeat password length cannot exceed 64 characters." }, widget=forms.PasswordInput() ) mobile_phone = forms.CharField( label='Mobile phone Number', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$'.'Mobile phone number format error'), ]) code = forms.CharField( label='Captcha', widget=forms.TextInput()) class Meta: model = models.UserInfo fields = ['username'.'email'.'password'.'confirm_password'.'mobile_phone'.'code'] class SendSmsForm(forms.Form) : mobile_phone = forms.CharField(label='Mobile phone Number', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$'.'Mobile phone number format error'),])def __init__(self, request, *args, **kwargs) : super().__init__(*args, **kwargs) self.request = request def clean_mobile_phone(self) : """ Hook for checking mobile phone number """ mobile_phone = self.cleaned_data['mobile_phone'] Determine if there is a problem with the SMS template tpl = self.request.GET.get('tpl') template_id = settings.TENCENT_SMS_TEMPLATE.get(tpl) if not template_id: # self.add_error('mobile_phone', 'SMS template error ') raise ValidationError('SMS template error') Check if there is a mobile phone number in the database exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists() if exists: raise ValidationError('Mobile phone number already exists') # texting code = random.randrange(1000.9999) # Send text messages sms = send_sms_single(mobile_phone, template_id, [code, ]) if sms['result'] != 0: raise ValidationError('SMS sending failed, {}'.format(sms['errmsg'])) # write to redis (Django-redis) conn = get_redis_connection() conn.set(mobile_phone, code, ex=60) return mobile_phone Copy the code
4. Click Register
4.1 Front end: Get data & send Ajax requests
- Collect data from the form (find each field)
- Data is sent to the background via Ajax [POST request]
register.html
Add the click register event function to the js part of the file, the code is as followsbindClickSubmit
Function to execute automatically after the page frame has loaded.
So instead of writing a URL, I’m going to reuse /register/, just to figure out what kind of request the user is sending
- The user sends the address anyway
GET
Request, then we directly let it jump to the registration page- When the user clicks register, the message is
POST
Request, then we carry out form validation & write to the database and other operations
{% block js %}
<script>
// The function is automatically executed after the page frame is loaded
$(function () {
bindClickBtnSms();
bindClickSubmit();
});
/* Click Submit */
function bindClickSubmit() {$('#btnSubmit').click(function () {$('.error-msg').empty();
// Collect the data in the form (find each field)
// Data is sent to the background via Ajax
$.ajax({
url: "{% url 'register' %}".type: "POST".data: $('#regForm').serialize(), // Get all key values in the form, including all field data + CSRF token
dataType: "JSON".success: function (res) {
if (res.status) {
location.href = res.data;
} else {
$.each(res.error, function (key, value) {$("#id_" + key).next().text(value[0]); })}})})}/* Click the button binding event */ to get the captcha
function bindClickBtnSms() {$('#btnSms').click(function () {$('.error-msg').empty();
// Get the phone number entered by the user
// Find the ID of the input box, obtain the value according to the ID, how to find the mobile phone ID?
// Django ModelForm generates fields with id_ + field names by default.
var mobilePhone = $('#id_mobile_phone').val();
// Send the Ajax request, and send the mobile phone number
$.ajax({
url: "{% url 'send_sms' %}".// Equivalent to /send/ SMS /
type: "GET".data: {mobile_phone: mobilePhone, tpl: "register"}, // Mobile phone number and registration template
dataType: "JSON".// Deserialize the data returned by the server into a dictionary
success: function (res) {
// The function that is automatically executed after the Ajax request is successfully sent: res is the value returned by the back end
if (res.status) {
sendSmsRemind();
} else {
// Error message
// console.log(res); // {status: False, error: {mobile_phone: [" error ",]}
$.each(res.error, function (key, value) {$("#id_" + key).next().text(value[0]); })}})})}/* Countdown */
function sendSmsRemind() {
var $smsBtn = $('#btnSms');
$smsBtn.prop('disabled'.true);
var time = 60;
var remind = setInterval(function () {
$smsBtn.val(time + 'Resend in seconds');
time = time - 1;
if (time < 1) {
clearInterval(remind);
$smsBtn.val('Click on the captcha code').prop('disabled'.false); }},1000)}</script>
{% endblock %}
Copy the code
4.2 the back-end
4.2.1 Data verification
- The verification is as follows:
- The user name, email address, and phone number are validated in the hook function
- The password is encrypted by MD5 and returned
- Md5 encryption is separately encapsulated in
utils
Add to folderencrypt.py
file
- Md5 encryption is separately encapsulated in
– python import uuid import hashlib
from django.conf import settings def md5(string): Hash_object = hashlib. MD5 (settings.secret_key.encode (' utF-8 ')) hash_object.update(string.encode(' utF-8 ')) return hash_object.hexdigest() def uid(string): Data = "{}-{}". Format (STR (uuid.uuid4()), string) return MD5 (data) - Verification code Is obtained by redis based on the phone number (key) and compared with the user input.Copy the code
- Modify the
forms/account.py
The file is as follows :(modified onlyRegisterModelForm
Class, otherwise unchanged.)
from utils import encrypt
class RegisterModelForm(BootStrapForm, forms.ModelForm) :
password = forms.CharField(
label='password',
min_length=8,
max_length=64,
error_messages={
'min_length': "Password length should not be less than 8 characters.".'max_length': "Password length cannot exceed 64 characters."
},
widget=forms.PasswordInput())
confirm_password = forms.CharField(
label='Double password',
min_length=8,
max_length=64,
error_messages={
'min_length': "Repeat password must be at least 8 characters long.".'max_length': "Repeat password length cannot exceed 64 characters."
},
widget=forms.PasswordInput()
)
mobile_phone = forms.CharField(
label='Mobile phone Number',
validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$'.'Mobile phone number format error'), ])
code = forms.CharField(
label='Captcha',
widget=forms.TextInput())
class Meta:
model = models.UserInfo
fields = ['username'.'email'.'password'.'confirm_password'.'mobile_phone'.'code']
def clean_username(self) :
username = self.cleaned_data['username']
exists = models.UserInfo.objects.filter(username=username).exists()
if exists:
raise ValidationError('Username already exists')
# self.add_error('username', 'username already exists ')
return username
def clean_email(self) :
email = self.cleaned_data['email']
exists = models.UserInfo.objects.filter(email=email).exists()
if exists:
raise ValidationError('Mailbox already exists')
return email
def clean_password(self) :
pwd = self.cleaned_data['password']
# encrypt & return
return encrypt.md5(pwd)
def clean_confirm_password(self) :
# pwd = self.cleaned_data['password']
pwd = self.cleaned_data.get('password')
confirm_pwd = encrypt.md5(self.cleaned_data['confirm_password'])
ifpwd ! = confirm_pwd:raise ValidationError('Two different passwords')
return confirm_pwd
def clean_mobile_phone(self) :
mobile_phone = self.cleaned_data['mobile_phone']
exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
if exists:
raise ValidationError('Mobile phone number registered')
return mobile_phone
def clean_code(self) :
code = self.cleaned_data['code']
# mobile_phone = self.cleaned_data['mobile_phone']
mobile_phone = self.cleaned_data.get('mobile_phone')
if not mobile_phone:
return code
conn = get_redis_connection()
redis_code = conn.get(mobile_phone)
if not redis_code:
raise ValidationError('Verification code invalid or not sent, please resend')
redis_str_code = redis_code.decode('utf-8')
ifcode.strip() ! = redis_str_code:raise ValidationError('Verification code error, please re-enter')
return code
Copy the code
4.2.2 Writing to the Database
- After data verification is successful, a record can be created in the database and jump to
/login/
Page (login page detailed in the next blog post) web/views/account.py
The code in the file is modified as follows :(only modifiedregister
The contents of the function remain the same.)
def register(request) :
"" "register "" "
if request.method == 'GET':
form = RegisterModelForm()
return render(request, 'register.html', {'form': form})
form = RegisterModelForm(data=request.POST)
if form.is_valid():
Write to database (password is ciphertext)
# data = form.cleaned_data
# data.pop('code')
# data.pop('confirm_password')
# instance = models.UserInfo.objects.create(**data)
# save() is the same code as above and will automatically weed out data that is not in the database
Select * from user where username = 'user';
form.save()
return JsonResponse({'status': True.'data': '/login/'})
return JsonResponse({'status': False.'error': form.errors})
Copy the code