报障系统概要

 

1.注册页面头像预览

方式一:

var obj = $(this)[0]  jQuery对象转化成DOM对象

var obj = $(this)[0].files 

var obj = $(this)[0].files[0];  获取上传文件的文件对象

<script>
    $(function () {
        bindAvatar1();
    });
    function bindAvatar1() {
        $('#imgFile').change(function () {
            var obj = $(this)[0].files[0];
            console.log(obj);
        })
    }
</script>

方式二:

window.URL.createObjectURL
function () { [native code] }

<script>
$(function () {
bindAvatar2();
});
/*
本地ajax上传
*/
function bindAvatar2() {
$('#imgFile').change(function () {
var obj = $(this)[0].files[0]; #先创建文件对象
//ajax发送到后台,并获取路径
//img.src = 获取路径
var v = window.URL.createObjectURL(obj); #获取要上传的图片文件路径
$('#previewImg').attr('src',v); 把路径赋值给src
})
}

如果上传图片到内存立即释放,会出现报错(window.URL.revokeObjectURL(v);)

    function bindAvatar2() {
        $('#imgFile').change(function () {
            var obj = $(this)[0].files[0];
            //ajax发送到后台,并获取路径
            //img.src = 获取路径
            var v = window.URL.createObjectURL(obj);
            $('#previewImg').attr('src',v);
            window.URL.revokeObjectURL(v);
        })
    }
View Code
function bindAvatar2() {
    $('#imgFile').change(function () {
        var obj = $(this)[0].files[0];
        //ajax发送到后台,并获取路径
        //img.src = 获取路径
        var v = window.URL.createObjectURL(obj);
        $('#previewImg').attr('src',v);
        $('#previewImg').load(function () {
            window.URL.revokeObjectURL(v);
        });
    })
}
function bindAvatar2改版

加载完成之后释放就能正常显示了

方式三:onload事件

    $(function () {
        bindAvatar3();
    });
    /*
    本地ajax上传
     */
    function bindAvatar3() {
        $('#imgFile').change(function () {
            var obj = $(this)[0].files[0];
            //ajax发送到后台,并获取路径
            //img.src = 获取路径
            var reader = new FileReader();
            reader.readAsDataURL(obj);
            reader.onload = function(){
                $('#previewImg').attr('src',this.result);
            }
        })
    }

 

window.URL.createObjectURL
function () { [native code] }

做if判断(if,else if,else) 用方式二和方式三兼容性较差,但是都是上传图片到内存,减轻图片上传到服务器的压力,方式一兼容性较好。
<script>
    $(function () {
        bindAvatar();
    });
    /*
    本地ajax上传
     */
    function bindAvatar() {
        if(window.URL.createObjectURL){
            bindAvatar2();
        }else if(window.FileReader){
            bindAvatar3();
        }else{
            bindAvatar1();
        }
    }
    function bindAvatar1() {
        $('#imgFile').change(function () {
            var obj = $(this)[0].files[0];
{#            console.log(obj);#}
            //ajax发送到后台,并获取路径
            //img.src = 获取路径
        })
    }
function bindAvatar2() {
    $('#imgFile').change(function () {
        var obj = $(this)[0].files[0];
        //ajax发送到后台,并获取路径
        //img.src = 获取路径
        var v = window.URL.createObjectURL(obj);
        $('#previewImg').attr('src',v);
        $('#previewImg').load(function () {
            window.URL.revokeObjectURL(v);
        });
    })
}
    function bindAvatar3() {
        $('#imgFile').change(function () {
            var obj = $(this)[0].files[0];
            //ajax发送到后台,并获取路径
            //img.src = 获取路径
            var reader = new FileReader();
{#            console.log('1');#}
            reader.readAsDataURL(obj);
            reader.onload = function(e){
{#                console.log('2');#}
                $('#previewImg').attr('src',this.result);
            }
        })
    }

</script>

 

方式四:FormData上传:

<script>
    $(function () {
        bindAvatar4();
    });
    /*
     本地ajax上传
     */

    function bindAvatar4() {
        $('#imgFile').change(function(){
            //$(this)[0]  #jQuery对象变成DOM对象
            //$(this)[0].files #获取上传当前文件的上传对象
            //$(this)[0].files[0]   #获取上传当前文件的上传对象的某个对象
            var obj = $(this)[0].files[0];
            console.log(obj);
            //ajax 发送给后台获取头像路径
            var formdata = new FormData();//创建一个对象
            formdata.append("file",obj);
            var xhr = new XMLHttpRequest();
            xhr.open("POST","/register/");
            xhr.send(formdata);

            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    var file_path = xhr.responseText;
                    console.log(file_path);
                    $("#previewImg").attr("src","/"+file_path)
                }
            }
        })
    }

</script>

 

2.注册页面

定义一个RegisterForm类和register函数:

- Form组件中通过构造方法可以封装自己想要的值
from django.forms import Form
from django.forms import fields
from django.forms import widgets
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from app01 import models

class RegisterForm(Form):
    username = fields.CharField(
        required=True,
        widget=widgets.TextInput(
            attrs={'class':'form-control','placeholder':'用户名为6-10个字符'}
        ),
        min_length=6,
        max_length=10,
        strip=True,
        error_messages={
            'required': '用户名不能为空',
            'min_length':'用户名至少为6个字符',
            'max_length':'用户名不超过10个字符',
        },
    )
    password = fields.CharField(
        required=True,
        widget=widgets.PasswordInput(
            attrs={'class':'form-control','placeholder':'密码为8-12个字符'}
        ),
        min_length=8,
        max_length=12,
        strip=True,
        validators=[
            RegexValidator(r'((?=.*\d))^.{8,12}$','必须包含数字'),
            RegexValidator(r'((?=.*[a-zA-Z]))^.{8,12}','必须包含字母'),
            # RegexValidator(r'((?=.*[^a-zA-Z0-9]))^.{8,12}','必须包含特殊字符'),
            # RegexValidator(r'^.(\s){8,12}','必须包含空格'),
        ],#用于对密码的正则验证
        error_messages={
            'required': '密码不能为空',
            'min_length':'密码不能少于8个字符',
            'max_length':'密码最多为12个字符!',
        }
    )
    password_again = fields.CharField(
        required=True,
        widget=widgets.PasswordInput(
            attrs={'class':'form-control','placeholder':'密码为8-12个字符'}
        ),
        min_length=8,
        max_length=12,
        strip=True,
        error_messages={'required':'请再次输入密码!',}
    )
    nickname = fields.CharField(
        required=True,
        widget=widgets.TextInput(
            attrs={'class':'form-control','placeholder':'请输入昵称'}
        )
    )
    email = fields.EmailField(
        required=True,
        widget=widgets.TextInput(attrs={'class':'form-control','placeholder':'请输入邮箱'}),
        # strip=True,
        # error_messages={'required':'邮箱不能为空','invalid':'请输入正确的邮箱格式'},
    )
    avatar = fields.FileField(widget=widgets.FileInput(attrs={'id':'imgFile','class':'f1'}))
    code = fields.CharField(widget=widgets.TextInput(attrs={'class':'form-control','placeholder':'请输入验证码'}))
    def clean_username(self):
        #对于username扩展验证,查看是否存在
        username = self.cleaned_data['username']
        users = models.UserInfo.objects.filter(username=username).count()
        if users:#如果用户名已存在
            raise ValidationError('用户名已经存在!')
        return username
    def clean_email(self):
        #对于email的扩展验证,查看是否存在
        email = self.cleaned_data['email']
        email_count = models.UserInfo.objects.filter(email=email).count()
        if email_count:
            raise ValidationError('邮箱已经存在!')
        return email
    # def _clean_password(self):#验证两次输入密码是否一致
    #     password1 = self.cleaned_data['password']
    #     password2 = self.cleaned_data['password_again']
    #     if password1 and password2:
    #         if password1 != password2:
    #             raise ValidationError('您两次输入的密码不一致')

    def __init__(self,request,*args,**kwargs):#构造方法,传request参数
        super(RegisterForm,self).__init__(*args,**kwargs)#完成原有form功能以外
        self.request = request#再封装一个request

    def clean_code(self):
        input_code = self.cleaned_data['code']
        session_code = self.request.session.get('code')#session取验证码
        if input_code.upper() == session_code.upper():#验证相等时
            return input_code#
        raise ValidationError('验证码错误')

    def clean(self):  # 验证两次输入密码是否一致
        p1 = self.cleaned_data.get('password')
        p2 = self.cleaned_data.get('password_again')
        if p1 == p2:
            # return self.cleaned_data
            return None
        # else:
        #     raise ValidationError('密码不一致')
        self.add_error("password_again",ValidationError('密码不一致')) #在页面的指定字段添加错误信息
   """
    Django源码添加错误信息
    # except ValidationError as e:
    # self.add_error(name, e)
   """
    # def clean(self):
    #     #基于form对象的验证,字段全部验证通过会调用clean函数验证
    #     self._clean_password()#调用函数
    #     p1 = self.cleaned_data['password']
    #     p2 = self.cleaned_data['password_again']
    #     return p2

            
forms.py RegisterForm类
def register(request):
    """
    用户注册
    :param request:
    :return:
    """
    if request.method == "GET":
        obj = RegisterForm(request)
        return render(request,'register.html',{'obj':obj})
    else:
        #验证码
        obj = RegisterForm(request,request.POST,request.FILES)
        if obj.is_valid():
            pass
        else:
            # print(obj.errors['__all__'])
            # print(obj.errors[NON_FIELD_ERRORS])
            """
            <ul class="errorlist nonfield"><li>密码不一致</li></ul>
            <ul class="errorlist nonfield"><li>密码不一致</li></ul>
           """
            #obj.errors是一个字典
            # - 对于Form组件错误信息
            """
            {
                __all__: [错误1,错误2]
            user: [错误1,错误2]
            password: [错误1,错误2]
            }
            """

        return render(request,'register.html',{'obj':obj})
register函数
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
    <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css">
    <style>
        .register {
            width: 600px;
            margin: 0 auto;
            padding: 20px;
            margin-top: 80px;
        }
        .f1{
            position: absolute;
            height: 80px;
            width: 80px;
            top: 0;
            left: 0;
            opacity: 0
        }
    </style>
</head>
<body>
<div class="register">
    <h3>用户注册</h3>

    <form class="form-horizontal" method="POST" target="ifr" action="/register/" enctype="multipart/form-data">
{#        <h3>{{ obj.non_field_errors }}</h3>#}
        {% csrf_token %}
        <div style="position: relative;width: 80px;height: 80px">
            <img id="previewImg" style="width: 80px;height: 80px" src="/static/images/default.png">
{#            <input id="imgFile" class="f1" style="" type="file">#}
            {{ obj.avatar }}
        </div>
        <div class="form-group">
            <label class="col-sm-2 control-label">用户名</label>
            <div class="col-sm-10">
{#                <input type="text" class="form-control" id="inputEmail3" placeholder="用户名" name="user">#}
                {{ obj.username }}{{ obj.errors.username.0 }}
            </div>
        </div>
        <div class="form-group">
            <label class="col-sm-2 control-label">密码</label>
            <div class="col-sm-10">
{#                <input type="password" class="form-control" placeholder="密码" name="pwd">#}
                {{ obj.password }}{{ obj.errors.password.0 }}
                <span class="pwd1"></span>
            </div>
        </div>

        <div class="form-group">
            <label class="col-sm-2 control-label">确认密码</label>
            <div class="col-sm-10">
{#                <input id="password" type="password" class="form-control" placeholder="确认密码" name="pwd2">#}
                    {{ obj.password_again }}{{ obj.errors.password_again.0 }}{{ obj.non_field_errors }}
                <span class="pwd2"></span>
            </div>
        </div>
        <div class="form-group">
            <label class="col-sm-2 control-label">昵称</label>
            <div class="col-sm-10">
{#                <input id="password_again" type="password" class="form-control" placeholder="昵称" name="nickname">#}
                {{ obj.nickname }}{{ obj.errors.nickname.0 }}
            </div>
        </div>

        <div class="form-group">
            <label class="col-sm-2 control-label">邮箱</label>
            <div class="col-sm-10">
{#                <input type="text" class="form-control" placeholder="邮箱" name="email">#}
                                    {{ obj.email }}{{ obj.errors.email.0 }}
            </div>
        </div>

        <div class="form-group">
            <label class="col-sm-2 control-label">验证码</label>
            <div class="col-sm-5">
{#                <input type="text" class="form-control" placeholder="验证码" name="Verification Code">#}
                                    {{ obj.code }} {{ obj.errors.code.0 }}
            </div>

            <div class="col-sm-5">
                <img style="width: 120px;height: 30px" src="/check_code/">
            </div>
        </div>


        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <input type="submit" class="btn btn-default" value="注册"/>
            </div>
        </div>
    </form>

</div>

<script src="/static/jquery-3.2.1.js"></script>
<script>
    $(function () {
        bindAvatar();
    });
    /*
     本地ajax上传
     */
    function bindAvatar() {
        if (window.URL.createObjectURL) {
            bindAvatar2();
        } else if (window.FileReader) {
            bindAvatar3();
        } else {
            bindAvatar1();
        }
    }
    function bindAvatar1() {
        $('#imgFile').change(function () {
            var obj = $(this)[0].files[0];
            {#            console.log(obj);#}
            //ajax发送到后台,并获取路径
            //img.src = 获取路径
        })
    }
    function bindAvatar2() {
        $('#imgFile').change(function () {
            var obj = $(this)[0].files[0];
            //ajax发送到后台,并获取路径
            //img.src = 获取路径
            var v = window.URL.createObjectURL(obj);
            $('#previewImg').attr('src', v);
            $('#previewImg').load(function () {
                window.URL.revokeObjectURL(v);
            });
        })
    }
    function bindAvatar3() {
        $('#imgFile').change(function () {
            var obj = $(this)[0].files[0];
            //ajax发送到后台,并获取路径
            //img.src = 获取路径
            var reader = new FileReader();
            {#            console.log('1');#}
            reader.readAsDataURL(obj);
            reader.onload = function (e) {
                {#                console.log('2');#}
                $('#previewImg').attr('src', this.result);
            }
        })
    }

    function bindAvatar4() {
        $('#imgFile').change(function(){
            //$(this)[0]  #jQuery对象变成DOM对象
            //$(this)[0].files #获取上传当前文件的上传对象
            //$(this)[0].files[0]   #获取上传当前文件的上传对象的某个对象
            var obj = $(this)[0].files[0];
            console.log(obj);
            //ajax 发送给后台获取头像路径
            var formdata = new FormData();//创建一个对象
            formdata.append("file",obj);
            var xhr = new XMLHttpRequest();
            xhr.open("POST","/register/");
            xhr.send(formdata);

            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    var file_path = xhr.responseText;
                    console.log(file_path);
                    $("#previewImg").attr("src","/"+file_path)
                }
            };
        })
    }

</script>

</body>
</html>
register.html

首先定义构造方法,使后端可以直接通过session取值,省去很多麻烦
def __init__(self,request,*args,**kwargs):#构造方法,传request参数
super(RegisterForm,self).__init__(*args,**kwargs)#完成原有form功能以外
self.request = request#再封装一个request
def register(request):
"""
用户注册
:param request:
:return:
"""
if request.method == "GET":
obj = RegisterForm(request)
return render(request,'register.html',{'obj':obj})
else:
#验证码
obj = RegisterForm(request,request.POST,request.FILES) #这里相应传一个request参数
if obj.is_valid():
pass
else:
# print(obj.errors['__all__'])
# print(obj.errors[NON_FIELD_ERRORS])
"""
<ul class="errorlist nonfield"><li>密码不一致</li></ul>
<ul class="errorlist nonfield"><li>密码不一致</li></ul>
"""
#obj.errors是一个字典
# - 对于Form组件错误信息
"""
{
__all__: [错误1,错误2]
user: [错误1,错误2]
password: [错误1,错误2]
}
"""

return render(request,'register.html',{'obj':obj})
在RegisterForm类中自定义clean_code函数
1.显示验证码错误信息
def clean_code(self):
input_code = self.cleaned_data['code']
session_code = self.request.session.get('code')#session取验证码
if input_code.upper() == session_code.upper():#验证相等时
return input_code#
raise ValidationError('验证码错误')
2.验证密码是否一致
def clean(self):  # 验证两次输入密码是否一致
p1 = self.cleaned_data.get('password')
p2 = self.cleaned_data.get('password_again')
if p1 == p2:
# return self.cleaned_data
return None
# else:
# raise ValidationError('密码不一致')
self.add_error("password_again",ValidationError('密码不一致'))

前端HTML获取错误信息 {{ obj.non_field_errors }}

class RegisterForm(Form):
    username = fields.CharField(
        widget=widgets.TextInput(attrs={'class':'form-control'})
    )
    password = fields.CharField(
        widget=widgets.PasswordInput(attrs={'class':'form-control'})
    )
    password2 = fields.CharField(
        widget=widgets.PasswordInput(attrs={'class':'form-control'})
    )
    avatar = fields.FileField(widget=widgets.FileInput(attrs={'id':"imgSelect",'class':"f1"  }))
    code = fields.CharField(
        widget=widgets.TextInput(attrs={'class':'form-control'})
    )

    def __init__(self,request,*args,**kwargs):
        super(RegisterForm,self).__init__(*args,**kwargs)
        self.request = request
Form组件中通过构造方法可以封装自己想要的值

 

- 对于Form组件错误信息
{
__all__: [错误1,错误2]
user: [错误1,错误2]
password: [错误1,错误2]
}

# 获取整体错误信息
- 后台
print(obj.errors['__all__'])
print(obj.errors[NON_FIELD_ERRORS])
- 模板
{{ obj.non_field_errors }}


Django源码关于form组件验证的流程:
is_valid()-->self.errors-->self.full_clean()-->{self._clean_fields() self._clean_form() self._post_clean()}
from django.core.exceptions import NON_FIELD_ERRORS--->NON_FIELD_ERRORS = '__all__'

按照源码添加错误信息
except ValidationError as e:
self.add_error(name, e)
self.add_error('字段名称',错误异常对象)

3.点击更换验证码

 

$('#i1').attr('src','/check_code/??')

<div class="col-sm-5">
<img onchange="changeCode(this);" id="i1" style="width: 120px;height: 30px" src="/check_code/" title="点击更新图片">
</div>
添加一个onchange事件
function changeCode(ths) {
ths.src = ths.src + "?";
}

 

posted on 2017-07-13 15:52  bigdata_devops  阅读(425)  评论(0编辑  收藏  举报

导航