django练手( 二十四):用户其它信息的修改

一、功能描述

  1. 用户访问信息修改页面,页面展示用户的信息:头像、邮箱、电话、地址。
  2. 用户点击编辑按钮,页面变成用户信息输入界面,输入框默认带有邮箱、电话、地址。同时,编辑按钮变成提交按钮。
  3. 用户编辑信息后提交,页面变成用户信息展示界面。
    具体功能如下图所示:
    image

二、实现思路

  1. 在用户信息界面,增加两个div,一个用来展示信息,一个用来编辑信息。
  2. 页面加载后,展示信息的div显示,编辑信息的div隐藏。用户点击编辑按钮后,展示信息的div隐藏,编辑信息的div展示。

三、技术要点

  1. 编辑信息的form初始值的设定。在form实例化的时候,使用initial参数。该参数的值是一个字典,字典的值就是form的初始值。

四、代码实现:

  1. 前端代码:前端代码在app-templates-app-userinfo.html中。主要有两个div和控制这两个div显示/隐藏的jquery组成。
    ① div部分的代码:
    <!--用户信息显示开始。页面加载时,这个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>
                <!--用户信息编辑结束-->
    
    ② Jquery部分的代码:
    <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>
    
  2. 后端代码:
    ① model部分。该部分代码在文件app-models.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)
    
    ② form部分。该部分代码在文件app-form-app-account.py中,具体如下:
    # 编辑用户信息(目前只有用户选择图标的功能)
    @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

posted @ 2024-01-15 18:35  喜气洋洋白云山  阅读(75)  评论(0编辑  收藏  举报