博客园项目
day 1
基于ajax,PIL实现随机图片验证码 以及geetest插件实现滑动验证码 的登录功能。
1)生成随机验证码
怎么实现呢?
前端html代码
贴上代码
<div class="row"> <div class="col-md-6"> <label for="id_valid">验证码</label> <input type="text" class="form-control" id="id_valid" placeholder="验证码"> </div> <div class="col-md-6"> <img src="/get_valid_code/" width="250px" height="50px" alt=""> //<img src='//'>src跟一个视图函数,走这个函数,拿到一个图片,会将页面重新渲染。 </div> </div>
点击实现刷新
<script> $('img').click(function () { console.log($(this)); // console.log r.fn.init [img] console.log($(this)[0]); // console.log <img src="http://127.0.0.1:8000/get_valid_code/?" width="250px" height="50px" alt> $(this)[0].src+='?' .src方法是DOM对象的方法 }) </script>
视图函数
def get_valid_code(request): from PIL import Image,ImageDraw,ImageFont from io import BytesIO def get_color(): return (random.randint(0,255),random.randint(0,255),random.randint(0,255)) def get_char(): random_num=str(random.randint(0,9)) random_upper=chr(random.randint(65,90)) random_lower=chr(random.randint(97,122)) return random.choice([random_num,random_upper,random_lower]) height=50 width=250 image=Image.new(mode='RGB',size=(width,height),color=get_color()) print('image',image,type(image)) #image <PIL.Image.Image image mode=RGB size=250x50 at 0x1E20FE94BA8> <class 'PIL.Image.Image'> draw=ImageDraw.Draw(image,mode='RGB') print('draw',draw,type(draw)) #draw <PIL.ImageDraw.ImageDraw object at 0x000001E20FE94CF8> <class 'PIL.ImageDraw.ImageDraw'> font=ImageFont.truetype('app01/static/kumo.ttf',40) valid_code='' for i in range(6): char=get_char() valid_code+=char draw.text([i*40,5],char,get_color(),font=font) f=BytesIO() image.save(f,'png') data=f.getvalue() print('data',data,type(data)) #data b'\x89PNG\...' <class 'bytes'>
request.session["valid_code"]=valid_code #将验证码放在session中
return HttpResponse(data)
2)点击登录,触发ajax提交事件
前端代码
$('#id_login').click(function () { $.ajax({ url:'/login/', type:'post', data:{username:$('#id_username').val(), password:$('#id_password').val(), csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(), valid_code:$('#id_valid').val() }, success:function (data) { if (data.status){ location.href='/index/' } else{ $('#id_login').next().text(data.error_msg); setTimeout(function () { $('#id_login').next().text('') },1000) } } }) })
后端代码
def login(request): if request.is_ajax(): username=request.POST.get('username') password=request.POST.get('password') valid_code=request.POST.get('valid_code') valid_CODE=request.session.get('valid_CODE') print(valid_CODE,valid_code) data={'status':None,'error_msg':None} if valid_code.lower()==valid_CODE.lower(): user=auth.authenticate(username=username,password=password) #验证有没有用户用auth.authenticate方法 print(user) if user: data['status']=1 else: data['status']=0 data['error_msg']='用户名或密码不存在!' else: data['status']=0 data['error_msg']='验证码不正确!' return JsonResponse(data) return render(request,'login.html')
day2
1 图像上传
前端
html代码
PS label标签的妙用
将<img>标签放在label标签内。这样在点击img标签的时候,就会触发label标签的事件,找到for='xx',在这里是找到<input type='file'>,会直接跳出其窗口。
’
<div class="form-group">
<label for="id_avator" class="col-sm-2 control-label">头像<img style="margin-left: 80px" width="50px" height="50px" class="pull-left" id='id_img_avator' src="/static/default.png"></label> <div class="col-sm-10"> <input type="file" class="form-control" id="id_avator" placeholder="" style="display:None"> </div> </div>
js代码
PS
FileReader():读取文件,从文件中读取数据和保存在js变量中。
参考知识网址:http://www.iunbug.com/archives/2012/06/04/220.html
用FileReader():从文件中读取数据,存储到JS变量中
<script> $('#id_avator').change(function () { //上传图片,change时间。 var file=$(this)[0].files[0]; var reader=new FileReader(); reader.readAsDataURL(file); reader.onload=function () { console.log(this); //FileReader {readyState: 2, result: "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD…oJDI5wRnHrmsm6kX3/OlSprsZj1Fwy/SevrSpUqeMLD//2Q==", error: null, onloadstart: null, onprogress: null, …} console.log(typeof this); //object $('#id_img_avator').attr('src',this.result) } }) </script>
test:测试 file,reader,this.result到底是什么东西。
$('#id_avator').change(function () { var file=$(this)[0].files[0]; console.log(file); console.log(typeof file); var reader=new FileReader(); console.log(reader); console.log(typeof reader); reader.readAsDataURL(file); reader.onload=function () { console.log(this.result); $('#id_img_avator')[0].src=this.result} });
输出:
File(17989) {name: "th.jpg", lastModified: 1513684937519, lastModifiedDate: Tue Dec 19 2017 20:02:17 GMT+0800 (中国标准时间), webkitRelativePath: "", size: 17989, …} (index):116 object (index):118 FileReader {readyState: 0, result: null, error: null, onloadstart: null, onprogress: null, …} (index):119 object (index):122 data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8...
2 $.each()方法
在js代码中
success:function (data) { if (data.user){ location.href='/index/' } else{ console.log(data.error_msg); $('span').text(''); $('.form-control').removeClass('has-error'); $.each(data.error_msg,function (i,j) { $('#id_'+i).next().addClass('pull-right').css('color','red').text(j[0]); if (i=='__all__'){ $('#id_re_password').next().addClass('pull-right').css('color','red').html(j[0]) } }) } }
data.error_msg是正宗的字典。
function(i,j) i 会取到key值,j会取到value值。value值是一个列表。
if i=='__all__',判断全局钩子,密码与确认密码是否一致。
3
$('#id_register').click(function () { var formdate=new FormData(); formdate.append('username',$('#id_username').val()); formdate.append('password',$('#id_password').val()); formdate.append('re_password',$('#id_re_password').val()); formdate.append('email',$('#id_email').val()); formdate.append('valid_code',$('#id_valid_code').val()); formdate.append('file_img',$('#id_avator')[0].files[0]); formdate.append("csrfmiddlewaretoken",$("[name='csrfmiddlewaretoken']").val()); $.ajax({ url:'/register/', type:'post', processData:false, contentType:false, data:formdate,
$('#id_avator')[0].files[0]是一个DOM对象,文件内容。
需要将它发送给后端,用到了FormData类。
后端代码
接收FormData,都在request.POST中。
经过is_valid()方法处理完后,数据都在cleaned_data和errors中。
文件是一个特殊的存在,它的发送和取出都与其他不一样。
def register(request): if request.is_ajax(): formregister = FormRegister(request,request.POST) regResponse={'user':None,'error_msg':None} if formregister.is_valid(): username=formregister.cleaned_data.get('username') password=formregister.cleaned_data.get('password') re_password=formregister.cleaned_data.get('re_password') email=formregister.cleaned_data.get('email') file_img=request.FILES.get('file_img') print('file_img',file_img,type(file_img)) UserInfo.objects.create_user(username=username,password=password,email=email,avatar=file_img) regResponse['user']=1
输出:
file_img th.jpg <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
4 Form组件继承request
forms.py 视为view.py 服务的
在views.py中,视图函数
def xxx(request):
formreg=FormReg(request,request.POST):
在form.py中
class FormReg(forms.Form)
def__init__(request,*args,**kwargs)
super().__init__(*args,**kwargs)
self.request=request
username=forms.Charfileld(..)
....
这样 在form组件中,利用钩子可以去到保存在request.session中的验证码,可以在钩子里对验证码进行判定。
解决了一个什么问题呢?
form组件本身是单纯的帮助建立form表单的,除此之外好像并无别的高端用法。
但form组件本质上是class类,类可以继承,在__init__的时候可以传参。
so,form组件在views.py文件中实例化 的时候便可以传参,传各种需要的参数。
将request传给form类,实例化的对象拿到request.session中的验证码。
ajax提交,用户输入的验证码在request.POST中,经过is_valid(),在cleaned_data或者errors中。搞定!这样便可以验证了。
高端的用法!