django练手( 二十四):用户其它信息的修改
一、功能描述
- 用户访问信息修改页面,页面展示用户的信息:头像、邮箱、电话、地址。
- 用户点击编辑按钮,页面变成用户信息输入界面,输入框默认带有邮箱、电话、地址。同时,编辑按钮变成提交按钮。
- 用户编辑信息后提交,页面变成用户信息展示界面。
具体功能如下图所示:
二、实现思路
- 在用户信息界面,增加两个div,一个用来展示信息,一个用来编辑信息。
- 页面加载后,展示信息的div显示,编辑信息的div隐藏。用户点击编辑按钮后,展示信息的div隐藏,编辑信息的div展示。
三、技术要点
- 编辑信息的form初始值的设定。在form实例化的时候,使用initial参数。该参数的值是一个字典,字典的值就是form的初始值。
四、代码实现:
- 前端代码:前端代码在app-templates-app-userinfo.html中。主要有两个div和控制这两个div显示/隐藏的jquery组成。
① div部分的代码:
② Jquery部分的代码:<!--用户信息显示开始。页面加载时,这个div显示在页面上。当用户点击编辑按钮时,这个div消失--> <div id="userinfo_show"> <div class="panel panel-default"> <div class="panel-heading"> <div class="row"> <div class="col-md-9"> <h1 class="display-3"> {{ request.user.last_name }}{{ request.user.first_name }} </h1> </div> <div class="col-md-2"> <div class="user_img" data-toggle="modal" data-target="#myModal" id="user_img_div"> <!--用户图标的显示位置,初始的图片路径是数据库用户表中的图片路径。当用户选择图片后,被选择图片的路径传给这个图片--> <img src="../../../{{ user_img_url }}" alt="" id="user_img"> </div> </div> </div> </div> <table class="table"> <tr> <td>电子邮件地址</td> <td>{{ request.user.email }}</td> </tr> <tr> <td>手机</td> <td>{{ request.user.phone_num }}</td> </tr> <tr> <td>地址</td> <td>{{ request.user.address }}</td> </tr> </table> </div> <input type="button" class="btn btn-default btn-custom" value="编辑" id="btnShow"> </div> <!--用户信息显示结束--> <!--用户信息编辑开始。页面加载时,这个div不在页面上显示。当用户点击编辑按钮时,这个div显示,用户信息显示的div消失--> <div id="userinfo_edit" style="display: none"> <div class="panel panel-default"> <div class="panel-heading"> <div class="row"> <div class="col-md-9"> <h1 class="display-3"> {{ request.user.last_name }}{{ request.user.first_name }} </h1> </div> <div class="col-md-2"> <div class="user_img" data-toggle="modal" data-target="#myModal" id="user_img_div"> <!--用户图标的显示位置,初始的图片路径是数据库用户表中的图片路径。当用户选择图片后,被选择图片的路径传给这个图片--> <img src="../../../{{ user_img_url }}" alt="" id="user_img"> </div> </div> </div> </div> <!--用户信息编辑的Form开始--> <form method="post" action="{% url 'app:new_userinfo_edit' %}" name="userinfo" id="userinfo"> {% csrf_token %} <table class="table"> {% for form in forms %} <tr> <td>{{ form.label }}</td> <td>{{ form }}<span class="error-msg"></span></td> </tr> {% endfor %} </table> </form> <!--用户信息编辑的Form结束--> </div> <input type="submit" class="btn btn-default btn-custom" value="提交" id="btnSubmit"> </div> <!--用户信息编辑结束-->
<script> $(document).ready(function () { avatarImgClick(); //选择头像的程序 btnShowClick(); //单击编辑按钮的程序 btnSubmit(); //单击提交按钮的程序 }) // 模态框里的信息被点击的时候 function avatarImgClick() { /* 当模态框里的图片被单击的时候: 1、被单击图片的路径赋给用户图标的图片; 2、模态框隐藏; 3、被单击图片的id和csrf_token组成data,通过ajax的data方法发送到后台。 */ $('.modal-body').on('click', 'img', function () { let img_src = $(this).attr("src"); $("#user_img").attr("src", img_src); $("#myModal").modal('hide'); let id = $(this).attr("id"); let CsrfToken = $("[name='csrfmiddlewaretoken']").val(); let data = {'csrfmiddlewaretoken': CsrfToken, "avatar_id": id}; $.ajax({ url: "{% url 'app:userinfo_edit' %}", type: "POST", // data: {"avatar_id": id}, data: data, dataType: "json", success: function (res) { if (res.status) { console.log("头像成功保存") } else { console.log(res.message) } }, error: function (res) { console.log("发送失败"); } }) }) } //编辑按钮被单击时,隐藏信息展示界面,呈现信息编辑界面 function btnShowClick() { /* 编辑按钮被单击时,执行两个动作: 1、用户信息展示的div消失; 2、用户信息编辑的div呈现。 * */ $("#userinfo_show").on("click","input",function (){ $("#userinfo_show").attr("style", "display:none"); $("#userinfo_edit").attr("style", "display:block"); }); } /* 提交按钮被单击时,把用户编辑form里的数据以ajax的方式提交后台。 如果提交成功,且修改了用户信息,隐藏信息编辑界面,呈现信息展示界面,同时刷新用户信息展示的div。 如果提交失败,或者修改用户信息没有成功,则什么也不做。 */ function btnSubmit() { $("#btnSubmit").click(function () { $('.error-msg').empty(); //清空错误信息 let data = $("#userinfo").serialize(); //获取form中的数据,.serialize() 方法创建以标准 URL 编码表示的文本字符串。它的操作对象是代表表单元素集合的 jQuery 对象 $.ajax({ url: "{% url 'app:new_userinfo_edit' %}", data: data, type: "post", dataType: "json", async: true, success: function (res) { if (res.status) { // 刷新用户信息展示的div,并把这个div显示在页面上 $("#userinfo_show").load(location.href + " #userinfo_show>*", "").attr("style", "display:block"); // 隐藏用户信息编辑的div $("#userinfo_edit").attr("style", "display:none"); console.log("修改成功了"); } else { // 如果修改用户信息失败,则把返回的错误信息循环展示在页面上 $.each(res.errors, function (key, value) { $("#id_" + key).next().text(value); }); console.log(res.errors) } }, error: function () { console.log("发送失败了") }, }); }) } </script>
- 后端代码:
① model部分。该部分代码在文件app-models.py中,具体如下:
② form部分。该部分代码在文件app-form-app-account.py中,具体如下:class MyUser(AbstractUser): phone_num = models.CharField(max_length=11, verbose_name='手机号', help_text='手机号是必填项') address = models.CharField(max_length=100, verbose_name='地址', blank=True, help_text='请输入地址') avatar = models.ForeignKey(to=Avatar, verbose_name='头像', blank=True, null=True, on_delete=models.DO_NOTHING)
③路由部分:# 编辑用户信息(目前只有用户选择图标的功能) @login_required def userinfo_edit(request): """ 1、如果是GET的访问方式,则在数据库中取得所用图标数据。 2、在GET的访问方式下,如果用户是登录状态,则在数据库中取得该用户图标的url,并和所有图标数据一起返回到前端。 3、在GET的访问方式下,如果用户是未登录状态,则只把所有图标数据返回给前端。 4、如果是POST的访问方式,从POST数据中获取图标的id。 5、如果图标id存在,且用户是登录状态,则把图标id保存到用户信息中,并把状态为真的值返回前端。 6、如果图标id不存在,或者用户没有登录,则把状态为False的值和错误信息返回前端。 """ if request.method == 'GET': # 获取所有的用户图标数据 avatars = Avatar.objects.filter(is_active=True).order_by('-id') # 如果当前用户是登录状态,获取当前用户的图标地址,并把所有用户图标地址返回到前端 if request.user.username: avatar_id = request.user.avatar_id user_img = Avatar.objects.filter(id=avatar_id).first() """ 生成用户信息编辑页面的form。里面的参数是form里面带的默认值。 这是我探索到的form的一个新功能。介绍这个方法的地址在https://studygyaan.com/django/how-to-give-initial-value-to-model-forms """ forms = UserinfoEdit(initial={ 'email': request.user.email, 'phone_num': request.user.phone_num, 'address': request.user.address, }) if user_img: user_img_url = user_img.img_url return render(request, 'app/userinfo.html', {"avatars": avatars, "user_img_url": user_img_url, "forms": forms}) else: return render(request, 'app/userinfo.html', {"avatars": avatars, "forms": forms}) else: return render(request, 'app/userinfo.html', {"avatars": avatars}) if request.method == 'POST': # 获取图标ID avatar_id = request.POST.get("avatar_id", "") if avatar_id and request.user.username: # 把图标ID赋值给用户的图标ID字端,并保存 request.user.avatar_id = avatar_id request.user.save() return JsonResponse({"status": True}) else: return JsonResponse({"status": False, "message": "用户没有登录,无法保存"}) """ 感觉这个视图的合理状态是与 userinfo_edit视图合并。分成两个视图,虽然功能没什么问题,但逻辑上总是怪怪的。 """ @login_required def new_userinfo_edit(request): if request.method == "POST": data = request.POST fields = UserinfoEdit(data) if fields.is_valid(): request.user.email = data.get("email", '') request.user.phone_num = data.get("phone_num", '') request.user.address = data.get('address', '') request.user.save() return JsonResponse({"status": True}) else: return JsonResponse({"status": False, "errors": fields.errors})
这部分代码在app-urls.py文件中,具体如下:from django.urls import path from app.views.app.account import * urlpatterns = [ path('register/', register, name='register'), # 注册的路由 path('login/', login_view, name='login'), # 登录的路由 path('logout/', auth_logout, name='logout'), # 注销的路由 path('changepwd/', change_password, name='change_password'), # 修改密码的路由 path('avatar/', avatar_upload, name='avatar_upload'), # 用户图标上传 path('delavatar/', avatar_del, name='avatar_del'), # 删除用户图标 path('userinfo/', userinfo_edit, name='userinfo_edit'), # 编辑用户信息 path('new_userinfo/', new_userinfo_edit, name='new_userinfo_edit'), # 用户信息编辑新 ]
本节代码已上传至gitee.com。仓库地址是:https://gitee.com/yanfenglucky/bokeyuan