Django实战博客系统,注册账号板块功能实例

功能概要

  • 基于 forms组件 和 Ajax 实现注册功能
  • 注册头像上传预览
  • 利用Ajax错误信息提示
  • 局部钩子:检查user是否已注册
  • 全局钩子:检查两次密码是否相同
  • 利用表格字段FileField上传头像图片
  • Media配置用户资源储存文件夹
  • 配置Media文件路径为可访问权限

效果

这里写图片描述


文件目录

这里写图片描述


配置media用户上传目录

setting.py

# 配置用户上传静态文件 media
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# 做别名
MEDIA_URL = '/media/'

url.py 设置访问权限

# media配置 打开该路径浏览器访问权限
from django.views.static import serve
from cnblog import settings

# media配置
re_path(r'media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT})

数据库FileField文件储存,重要!!

这里写图片描述


注册页面HTML

Ajax传头像图片
头像预览(加载完再预览)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册新用户</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <style>
        #avatar_img{
            margin-left: 20px;
        }
        #avatar{
            display: none;
        }
        .error{
            color: red;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">
            <form action="">
                {% csrf_token %}
                {% for filed in form %}
                    <div class="form-group">
                        {# iled.auto_id 自动获取渲染id  就可以通过点击label焦点标签 #}
                        <label for="{{ filed.auto_id }}">{{ filed.label }}</label>
                        {{ filed }} <span class="error pull-right">{{ filed.errors.0 }}</span>
                    </div>
                {% endfor %}
                <div class="form-group">
                    {# 思路:利用label点击,引导等同于点击file按钮,再把file隐藏显示即可#}
                    <label for="avatar">
                        头像
                        <img id='avatar_img' width="60px" height="60px" src="/static/blog/img/default.png" alt="">
                    </label>
                    <input type="file" id="avatar">
                </div>
                {# 后面加span 错误提示 #}
                <input type="button" class="btn btn-default reg_btn" value="注册"><span class="error"></span>
            </form>
        </div>
    </div>

</div>
</body>
<script src="/static/blog/js/jquery-3.3.1.min.js"></script>
<script>

    // 头像预览
    // change事件来获取,用户选择头像
    $('#avatar').change(function () {
        // 获取用户选中的文件对象
        var file_obj=$(this)[0].files[0];
        // 获取文件对象的路径,文件阅读器
        var reader=new FileReader()
        // 阅读文件路径,返回到reader.result中
        reader.readAsDataURL(file_obj)
        // 读有延时,必须等待加载完后执行才会显示
        reader.onload=function(){
            // 修改img的src路径
            $('#avatar_img').attr('src',reader.result)
        }
    })


    // 基于Ajax提交数据
    $('.reg_btn').click(function () {
        var formData=new FormData() // 有文件对象所以用formData
        formData.append('user',$('#id_user').val());  //forms渲染格式:id_标签名
        formData.append('pwd',$('#id_pwd').val());
        formData.append('re_pwd',$('#id_re_pwd').val());
        formData.append('email',$('#id_email').val());
        formData.append('avatar',$('#avatar')[0].files[0]); //固定语法取文件
        formData.append('csrfmiddlewaretoken', $("[name='csrfmiddlewaretoken']").val());

        $.ajax({
            url:'',
            type:'post',
            // 不去处理发送的数据
            processData:false,
            //不去设置Content-Type请求头
            contentType:false,
            data:formData,
            success:function (data) {
                if(data.user){
                    //注册成功 跳转页面
                    location.href='/login/'
                }
                else{
                    //每次都必须先清空错误信息,否则上次的错误信息还会留着
                    $('span.error').html('')
                    $('.form-group').removeClass('has-error')
                    //注册失败 循环把错误信息放在对应窗口下
                    $.each(data.msg,function (field,error_list) {
                        //单独判断全局钩子
                        if(field=='__all__'){

                            $('#id_re_pwd').next().html(error_list[0]).parent().addClass('has-error')
                        }
                        //通过id找到是那个标签出错  .next() 找到错误提示span标签,再取[0]错误提示信息
                        $('#id_'+field).next().html(error_list[0])
                        //找到对应div 利用boot样式增加class制作红色边框提示
                        $('#id_'+field).parent().addClass('has-error')
                    })
                }
            }
        })
    })

</script>
</html>

自定义的forms模块

校验语法
全局钩子
局部钩子

from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError  # 钩子模块
from blog.models import UserInfo

class UserForm(forms.Form):
    user = forms.CharField(
        min_length=4,
        max_length=32,
        label='用户名',
        widget=widgets.TextInput(attrs={
            'class': 'form-control',
        }),
        error_messages={
            'required': '用户名不能为空',
            'min_length': '长度不小于4',
        },
    )
    pwd = forms.CharField(
        min_length=4,
        max_length=32,
        label='密码',
        widget=widgets.PasswordInput(attrs={
            'class': 'form-control',
        }),
        error_messages={
            'required': '不能为空',
            'min_length': '长度不小于4',
        },
    )
    re_pwd = forms.CharField(
        min_length=4,
        max_length=32,
        label='确认密码',
        widget=widgets.PasswordInput(attrs={
            'class': 'form-control',
        }),
        error_messages={
            'required': '不能为空',
            'min_length': '长度不小于4',
        },
    )
    email = forms.EmailField(
        max_length=32,
        label='邮箱地址',
        widget=widgets.EmailInput(attrs={
            'class': 'form-control',
        }),
        error_messages={
            'required': '不能为空',
        },
    )

    # 局部钩子---查看是否已经存在用户
    def clean_user(self):
        user = self.cleaned_data.get('user')
        user_new = UserInfo.objects.filter(username=user).first()
        if not user_new:
            return user  # 如果没有那么直接返回干净数据
        else:
            raise ValidationError('该用户已注册')  # 钩子错误提示语法

    # 全局钩子---判断2次密码是否输入一致
    def clean(self):
        pwd = self.cleaned_data.get('pwd')
        re_pwd = self.cleaned_data.get('re_pwd')
        if pwd and re_pwd:  # 判断如果一个都不通过的情况
            if pwd == re_pwd:
                return self.cleaned_data  # 成功返回干净数据
            else:
                raise ValidationError('两次密码不一致')  # 错误信息储存到errors{'__all__':[e,]}
        else:
            return self.cleaned_data

视图中检测

头像上传储存技术
校验输入合法性

def register(request):
    """
    注册功能
    :param request:
    :return:
    """
    if request.method == 'POST':
        form = UserForm(request.POST)
        # 用json返回 ajax
        response = {'user': None, 'msg': None}
        if form.is_valid():  # 输入正确,开始创建
            response['user'] = form.cleaned_data.get('user')  # 返回干净数据
            # 生产一个用户记录  必须用auth 的命令create_user创建加密的记录
            user = form.cleaned_data.get('user')
            pwd = form.cleaned_data.get('pwd')
            email = form.cleaned_data.get('email')
            avatar_obj = request.FILES.get('avatar')  # 文件对象 头像图片

            # 如果没有传头像那就不填,让他用默认图片
            extra = {}
            if avatar_obj:
                extra['avatar'] = avatar_obj
            UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)  # 字典用**传
        else:
            response['msg'] = form.errors
        return JsonResponse(response)

    else:
        form = UserForm()  # 模版渲染标签
        return render(request, 'register.html', {'form': form})

猜你喜欢

转载自blog.csdn.net/weixin_42329277/article/details/81990297