2.1博客系统 |基于form组件和Ajax实现注册登录
基于forms组件和Ajax实现注册功能
1 基于forms组件设计注册页面
--点击头像 === 点击input
--头像预览:
修改用户选中的文件对象;获取文件对象的路径;修改img的src属性,src=文件对象路径。
forms组件不仅可以校验字段值,还可以渲染标签(3种方法)
login.html
<a href="/register/" class="btn btn-success pull-right">注册</a>
1.基于forms组件的注册页面设计
修改 获取用户选中的文件对象;获取文件对象的路径;修改img标签的src属性,让src=文件对象路径。
register.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/blog/bootstrap/css/bootstrap.css"> {# <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css">#} <style type="text/css"> #avatar_img{ //给它加一个css样式 margin-left: 20px; } #avatar{ display: none; //设置让它隐藏起来,写到css里边 } </style> <script> window.onload= function () { //window.onload事件--->>> $("#id_user").val("hello"); //下面所有的标签都执行加载完之后,你再给我加载这句话。它执行到这一步的时候只是把这个事件绑定下并不会执行里边的代码 } </script> </head> <body> <h3>注册页面</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-lg-offset-3"> <form> {% csrf_token %} {% for field in form %} {# for 循环这个form,也就是user、pwd、re_pwd、email这些字段,进行渲染#} <div class="form-group"> //<label for="user">{{ field.label }}</label> //label里边for的值和input标签id的值一样,点击label就相当于点击input标签
<label for="{{field.auto_id}}"> {{field.label}} </label> #不要写死了,渲染出:for = "id_user"与下面input标签的id=“id_user”一样 {{ field }} {#这个它渲染出来有input标签,会跟字段的名字一致,只不过在这里要发ajax;给它加一个"class":"form-control"页面就变好看了#} </div> {% endfor %}
#########################################注册页面的头像预览,默认头像 <div class="form-group"> {#把头像没有放到input里边,把它单独处理了,它不需要校验#} <label for="avatar"> 头像 // 点击头像就相当于点击input标签 //把这个img标签放到label标签里边 <img id="avatar_img" width="60" height="60" src="/static/blog/img/default.png" alt=""> //点击img标签就相当于点击input </label> <input type="file" id="avatar" > //这时候这个标签就没有意义了,把它隐藏起来就可以了。style=“display:none" </div> <input type="button" class="btn btn-default reg_btn" value="submit"><span class="error"></span> <a href="/register/" class="btn btn-success pull-right">注册</a> </form> </div> </div> </div> <script src="/static/js/jquery-3.2.1.min.js"></script> <script> //头像预览 </script> </body> </html>
Myforms.py
from django import forms from django.forms import widgets from blog.models import UserInfo from django.core.exceptions import NON_FIELD_ERRORS, ValidationError class UserForm(forms.Form): user=forms.CharField(max_length=32, error_messages={"required": "该字段不能为空"}, label="用户名", widget=widgets.TextInput(attrs={"class":"form-control"},)) #label标签,这样子它就渲染出中文了 pwd = forms.CharField(max_length=32,label="密码", widget=widgets.PasswordInput(attrs={"class":"form-control"},)) re_pwd = forms.CharField(max_length=32,label="确认密码", widget=widgets.PasswordInput(attrs={"class":"form-control"},)) email = forms.EmailField(max_length=32,label="邮箱", widget=widgets.EmailInput(attrs={"class":"form-control"},))
2.注册页面的默认头像
把img标签写到label里边去,点击头像就相当于点击input标签
http://127.0.0.1:8000/static/blog/img/default.png,这样子就可以访问到这个默认的注册头像
很多网站是这样子:把input标签的长宽跟这个头像一致,然后利用css里边定位position=absolute,把这两个标签定位到一个位置上去。再把input标签透明度显示为0,这时候它俩叠到一起了,你点击头像也就点击了input标签。 另外一种思路是:利用label标签的for的值与input标签的id值一致就可以了,点击label相当于点击input标签。
3.注册页面的头像预览功能
Console--->>
$("#avatar") r.fn.init [input#avatar]0: input#avatarlength: 1__proto__: Object(0) $("#avatar")[0] <input type="file" id="avatar"> $("#avatar")[0].files FileList {0: File(593239), length: 1}0: File(593239) {name: "distance.png", lastModified: 1510650980163, lastModifiedDate: Tue Nov 14 2017 17:16:20 GMT+0800 (中国标准时间), webkitRelativePath: "", size: 593239, …}length: 1__proto__: FileList $("#avatar")[0].files[0] File(593239) {name: "distance.png", lastModified: 1510650980163, lastModifiedDate: Tue Nov 14 2017 17:16:20 GMT+0800 (中国标准时间), webkitRelativePath: "", size: 593239, …}
头像预览:
修改用户选中的文件对象;获取文件对象的路径;修改img的src属性,src=文件对象路径。
<script> //头像预览 $("#avatar").change(function () { //change事件,选中文本之后事件就发生了 //获取用户选中的文件对象 $(this)就是这个input标签 var file_obj = $(this)[0].files[0]; //获取文件对象的路径 var reader = new FileReader(); //基于一个文件阅读器,类实例化 reader.readAsDataURL(file_obj); //只要文件的路径,把文件传进去; FileReaderURL是读取文件的URL,读完之后把会它结果放在reader内置的对象里边,没有返回值 //修改img的src属性 , src=文件对象的路径 reader.onload= function () { //等加载完之后才执行里边的代码,这样子就可以预览了。onload事件 $("#avatar_img").attr("src",reader.result) //结果在reader.result里边 }; }); </script>
4.基于Ajax提交formdata数据
点击提交(什么都不输入直接submit)的错误信息在这里边:---->>> { user:null,msg:{ } }
//基于Ajax提交数据 $(".reg_btn").click(function () { console.log($("#form").serializeArray()); //找到form这个标签,打印下,它会对这里边的所有有效控件进行整理。见下面截图,(5)[{..}, {..}, {..}, {..}, {..} ] var formdata = new FormData(); //对下面注释内容的优化版本 var request_data = $("#form").serializeArray(); $.each(request_data, function (index, data) { //循环这个request_data,键是index, 值是form的有效控件data formdata.append(data.name,data.value) //每循环一次append一次 }); formdata.append("avatar", $("#avatar")[0].files[0]); //最后再把这个avatar文件单独加下 {# var formdata = new FormData(); //Ajax上传文件一定要换成FormData的格式,构建一个对象传到这里边#} {# formdata.append("user",$("#id_user").val()); //传过去的键和值#} {# 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", contentType:false, //要加两个参数不然会报错;数据的编码类型 processData:false, //只要是formdata都要加这两个参数 data: formdata, //把上边formdata构建出来之后,加到这里边来 success: function (data) { console.log(data);
##########################################5.基于Ajax在注册页面显示错误信息。############# if(data.user){ //注册成功,跳转登录页面 location.href = "/login/" } else{//注册失败 //console.log(data.msg) 把错误信息msg取出来 $("span.error").html(""); //清空错误信息 $(".form-group").removeClass("has-error"); //把边框的颜色去掉 //展示此次提交的错误信息 $.each(data.msg, function(field, error_list){ //依次循环msg这个object,function里边是循环的键值,键是每个错误字段的字符串,值是错误信息的列表。 console.log(field, error_list); //赋值, //field错误字段叫的名字 和input标签的id值是有关联的 if (field == "__all__"){ //处理全局错误信息;下面找到它的标签,父标签给它加上 $("#id_re_pwd").next().html(error_list[0]).parent().addClass("has-error"); } $("#id_"+field).next().html(error_list[0]); //每次循环都把各自的错误信息放到input标签的span标签里面。.next()是找它的下一个标签即span标签 $("#id_"+field).parent().addClass("has-error"); //变颜色 }) } } }) })
views.py
def register(request): if request.is_ajax(): #你点击那个按钮既是Ajax请求又是post请求。既可以用Ajax也可用method=post作分支判断 print(request.POST) #把所有提交的数据都取出来 form = UserForm(request.POST) #用UserForm做检验, response = {"user":None, "msg":None} #发Ajax一般都会返回一个字典来进行标示这些行为 if form.is_valid(): #数据全通过,成功 response["user"] = form.cleaned_data.get("user") #成功了让它等于 = 注册人的名字 else: #失败了-->> print(form.cleaned_data) #干净数据都在这里边 print(form.errors) #错误数据都在这里边 response["msg"] = form.errors #失败了之后把这所有的错误信息放到msg里边 return JsonResponse(response) form = UserForm() return render(request,"register.html", {"form":form})
5. 基于Ajax在注册页面显示错误信息
<style type="text/css"> .error{ color:red; //给错误信息加的css样式 } </style>
代码见上
id_user的父标签是form-group--->>给它加一个叫addClass的方法,相当于这个标签多了个叫has-error的名字
6.forms组件的局部钩子与全局钩子的应用
Myforms.py
from blog.models import UserInfo from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
def clean_user(self): val=self.cleaned_data.get("user") user = UserInfo.objects.filter(username=val).filter() if not user: return val else: raise ValidationError("该用户已注册") 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("两次密码不一致") #全局错误 else: return self.cleaned_data
views.py
from blog.Myforms import UserForm #引入即可
全局错误可以在视图里边取出来,跟之前form表单提交错误信息不一样,之前是把错误信息放到视图里边,放到模板里边去。这里可以直接在register里边
错误信息在errors里边,里边有个键叫__all__,对应列表error_list的信息,发给ajax了,ajax拿到数据做下判断---->>>
if (field == "__all__"){ //处理全局错误信息;下面找到它的标签,父标签给它加上 $("#id_re_pwd").next().html(error_list[0]).parent().addClass("has-error"); //给它放到re_pwd确认密码的下面 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人