BBS注册功能

一、项目注册功能编写步骤概览

  • 渲染前端标签
  • 校验用户数据
  • 展示错误提示

二、项目注册功能编写步骤详细

1. 开设路由跳转

# 注册功能
path('register/', views.register_func, name='register_view'),

2.写视图函数

from django.shortcuts import render, HttpResponse, redirect


def register_func(request):
    return render(request, 'registerPage.html', locals())

3.创建前端html注册页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
    <div class="container">
        <div class="col-md-8 col-md-offset-2">
            <h2 class="text-center">用户注册</h2>
           
        </div>
    </div>

4.写forms校验类

from django import forms
from app01 import models


class RegisterForm(forms.Form):
    """用户注册form类"""
    username = forms.CharField(min_length=3, max_length=8, label='用户名',
                               error_messages={
                                   'min_length': '用户名最短三位',
                                   'max_length': '用户名最长八位',
                                   'required': '用户名不能为空'
                               },
                               widget=forms.widgets.TextInput(attrs={'class': 'form-control'})
                               )

    password = forms.CharField(min_length=3, max_length=8, label='密码',
                               error_messages={
                                   'min_length': '密码最短三位',
                                   'max_length': '密码最长八位',
                                   'required': '密码不能为空'
                               },
                               widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
                               )

    confirm_password = forms.CharField(min_length=3, max_length=8, label='确认密码',
                                       error_messages={
                                           'min_length': '密码最短三位',
                                           'max_length': '密码最长八位',
                                           'required': '密码不能为空'
                                       },
                                       widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
                                       )

    email = forms.EmailField(label='邮箱',
                             error_messages={
                                 'required': '密码不能为空',
                                 'invalid': '邮箱格式不正确'
                             },
                             widget=forms.widgets.EmailInput(attrs={'class': 'form-control'})
                             )

    # 局部钩子校验用户名是否已存在
    def clean_username(self):
        username = self.cleaned_data.get('username')
        res = models.UserInfo.objects.filter(username=username)
        if res:
            self.add_error('username', '用户名已存在')
        return username

    # 全局钩子校验两次密码是否一致
    def clean(self):
        password = self.cleaned_data.get('password')
        confirm_password = self.cleaned_data.get('confirm_password')
        if not password == confirm_password:
            self.add_error('confirm_password', '两次密码不一致')
        return self.cleaned_data

5.在views.py里注册视图函数产生forms类对象

    # 1.先产生一个空的form_obj
    form_obj = myforms.RegisterForm()

6.前端渲染注册样式

            <form id="form">  <!--不使用form表单提交数据 但是用一下form标签 它有一个序列化功能-->
                {% csrf_token %}
                {% for form in form_obj %}
                    <div class="form-group">  <!--目的是让多个获取用户数据的标签上下间距更大一些-->
                        <label for="{{ form.auto_id }}">{{ form.label }}</label>  <!--form.auto_id自动获取渲染的标签id值-->
                        {{ form }}
                        <span style="color: red" class="pull-right"></span>
                    </div>
                {% endfor %}
                <!--用户头像自己编写相关标签获取-->
                <div class="form-group">
                    <label for="myfile">头像
                        <img src="/static/img/default.jpg" alt="" width="120" id="myimg">
                    </label>
                    <input type="file" id="myfile" style="display: none">
                </div>
                <input type="button" id="subBtn" class="btn btn-primary btn-block" value="注册">
            </form>

7.头像实时展示 绑定点击事件 发送Ajax请求

    <script>
        // 1.用户头像的实时展示
        $('#myfile').change(function () {
            // 1.产生一个文件阅读器对象
            let myFileReaderObj = new FileReader();
            // 2.获取用户上传的头像文件
            let fileObj = this.files[0];
            // 3.将文件对象交给阅读器对象读取
            myFileReaderObj.readAsDataURL(fileObj);
            // 等待文件阅读器对象加载完毕之后再修改src
            myFileReaderObj.onload = function () {
                // 4.修改img标签的src属性展示图片
                $('#myimg').attr('src', myFileReaderObj.result)
            }
        })

        // 2.给注册按钮绑定点击事件 发送ajax  携带了文件数据
        $('#subBtn').click(function () {
            // 1.先产生一个内置对象
            let myFormDataObj = new FormData();
            // 2.添加普通数据(单个单个的编写效率极低)
            $.each($('#form').serializeArray(), function (index, dataObj) {  // 对结果for循环 然后交给后面的函数处理
                myFormDataObj.append(dataObj.name, dataObj.value)  // {'name':'','value':''}
            })
            // 3.添加文件数据
            myFormDataObj.append('avatar', $('#myfile')[0].files[0])
            // 4.发送ajax请求
            $.ajax({
                url:'',
                type:'post',
                data:myFormDataObj,

                contentType:false,
                processData: false,

                success:function (args) {
                    if(args.code === 10000){
                        window.location.href = args.url
                    }else{
                        let dataObj = args.msg;
                        // 如何针对性的渲染错误提示 {'username'}  id_username
                        $.each(dataObj, function (k, msgArray) {
                            // 拼接标签的id值
                            let eleId = '#id_' + k
                            // 根据id查找标签 修改下面span标签的内容 并给父标签添加错误样式
                            $(eleId).next().text(msgArray[0]).parent().addClass('has-error')

                        })
                    }
                }


            })
        })

        // 3.给所有的input标签绑定获取焦点事件 移除错误样式
        $('input').focus(function () {
            $(this).next().text('').parent().removeClass('has-error')
        })
    </script>

8.后端注册功能正确的业务逻辑

    if request.method == "POST":
        form_obj = myforms.RegisterForm(request.POST)  # username password confirm_password email csrfmiddlewaretoken
        if form_obj.is_valid():
            clean_data = form_obj.cleaned_data  # 存储符合校验的数据 {username password confirm_password email}
            # 将confirm_password键值对移除
            clean_data.pop('confirm_password')  # {username password  email}
            # 获取用户上传的头像文件
            avatar_obj = request.FILES.get('avatar')  # 用户有可能没有上传
            if avatar_obj:
                clean_data['avatar'] = avatar_obj  # {username password  email avatar }
            # 创建用户数据
            models.UserInfo.objects.create_user(**clean_data)  # 上述处理字典的目的就是为了创建数据省事
            back_dict['msg'] = '注册成功'
            back_dict['url'] = '/login/'

9.后端注册功能错误的业务逻辑

     # 前后端ajax交互 通常采用字段作为交互对象
    back_dict = {'code': 10000, 'msg': ''}
    
            else:
            back_dict['code'] = 10001
            back_dict['msg'] = form_obj.errors
        return JsonResponse(back_dict)

10.注册功能展示效果图

image