• 实战之BBS(仿博客园写一个论坛)(二)登录页面,网站首页的实现


    一.登录页面

    1.效果展示:

    2.技术点:

    2.1验证码:验证码这个功能用了Image,ImageDraw,ImageFont,random,BytesIO模块和session

    Image是新创建一个图片,ImageDraw相当于在这个图片上创建一个画笔,ImageFont指定字体的格式

    random随机模块,BytesIO开辟一片字节类型的内存空间,session用于存储验证码,验证码的具体细节请看上篇博客

    2.2登录验证:我们的注册的时候,用的是auth.create_user()方法,这种方法会让我们的密码被加密,在数据库中如下图所示:

    所以说我们只能把从前端的获取的密码,经过同样的加密之后再和数据库中的数据进行比对

      user=auth.authenticate(request,username=username,password=password)

    如果user存在,登录成功,保持登录状态,否则返回错误信息,并对前端进行渲染

    2.2.1登录成功:

    首先用auth.login把user绑定,相当于session和cookie但是使用方法比这两个都简单,执行之后,不退出登录的情况下,request.user就是auth.login(request,user)里面的user

    auth.login(request,user)

    登录成功之后,给前端返回数据,首先在函数开头定义一个response_msg用于标识成功或失败,初始化:

     respone_msg={'code':100,'msg':''}

    当登录成功的时候,code不变,给response添加一个URL:

      respone_msg['url']='/home'

    当登录成功的时候,跳转到home页面。当然了这行代码也需要前端的配合,前端:

    success:function (data) {
                    if(data.code==100){
                        location.href=data.url
                    }

    2.2.2登录失败:

    登录失败,response_msg['code']变为101(或者随意一个数,和成功区别开就好),msg变为失败的信息,比如是验证码出错还是账号密码错误

    把返回的msg数据在前端进行渲染,显示出来,效果如下:

    3.流程图:

     4.具体代码:

    后端代码:

    from django.shortcuts import render,HttpResponse,redirect
    from app01 import myforms
    from app01 import models
    from django.http import JsonResponse
    # Create your views here.
    from PIL import Image,ImageDraw,ImageFont
    from io import BytesIO,StringIO
    from django.contrib import auth
    import random
    #随机数据
    def r_num(number):
        if number==2:
            return random.randint(0,128),random.randint(0,128),random.randint(0,128)
        if number == 1:
            return random.randint(128, 255), random.randint(128, 255), random.randint(128, 255)
    #验证码函数
    def yzm(request):
        yzm_img=Image.new("RGB",(260,40),r_num(1))
        draw=ImageDraw.Draw(yzm_img)
        font=ImageFont.truetype('static/1.ttf',40)
        code=''
        for i in range(5):
            random_num=str(random.randint(0,9))
            random_up=str(chr(random.randint(65,90)))
            random_low=str(chr(random.randint(97,122)))
            random_code=random.choice([random_num,random_up,random_low])
            draw.text((20+40*i,-5),random_code,r_num(2),font)
            code+=random_code
        io_obj=BytesIO()
        yzm_img.save(io_obj,'png')
        request.session['code']=code
        return HttpResponse(io_obj.getvalue())
    #登录函数
    def login(request):
        respone_msg={'code':100,'msg':''}
        if request.method=='POST':
            username=request.POST.get('username')
            password=request.POST.get('password')
            yzm=request.POST.get('yzm')
    
            if request.session.get('code').upper()==yzm.upper():
                user=auth.authenticate(request,username=username,password=password)
                if user:
                    auth.login(request,user)
                    respone_msg['url']='/home'
                else:
                    respone_msg['code']=101
                    respone_msg['msg']='用户名或密码错误'
            else:
                respone_msg['code']=102
                respone_msg['msg']='验证码错误'
            return  JsonResponse(respone_msg)
        return render(request,'login.html',locals())
    后端代码

    前端:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
    <div class="container">
        <h1 class="text-center">登录页面</h1>
        <div class="row">
            <form class="col-lg-offset-3 col-lg-6">
                {% csrf_token %}
                <div class="form-group">
                    <label for="id_username">用户名</label>
                    <input type="text" class="form-control" id="id_username" placeholder="用户名">
                </div>
                <div class="form-group">
                    <label for="id_password">密码</label>
                    <input type="password" class="form-control" id="id_password" placeholder="密码">
                </div>
                <div class="form-group">
                    <label for="id_yzm">验证码</label>
                    <input type="text" class="form-control" id="id_yzm" placeholder="验证码">
                    <div style="margin-top: 30px"><img src="/yzm/" alt="" id="img_yzm"></div>
                </div>
                <div><input type="button" id="button_id" value="登录" class="btn btn-primary"></div>
                <div> <span id="error" style="color: red"></span></div>
            </form>
        </div>
    </div>
    <script>
        $('#img_yzm').click(function () {
             var path2 = $(this).attr('src');
            $(this).attr('src',path2+='?')
        });
        $('#button_id').click(function () {
            $.ajax({
                url:'',
                type:'post',
                data:{
                    'username':$('#id_username').val(),
                    'password':$('#id_password').val(),
                    'yzm':$('#id_yzm').val(),
                    'csrfmiddlewaretoken':$("[name='csrfmiddlewaretoken']").val()
                },
                success:function (data) {
                    if(data.code==100){
                        location.href=data.url
                    }
                    else {
                        $('#error').html(data.msg)
                    }
                }
            })
        })
    </script>
    </body>
    </html>
    
    前端代码
    前端

    二.首页的实现

    1.效果展示:

    ,上图可以分为左右两边面板模块,中间文章展示模块,页面顶部导航栏模块,顶部导航栏模块分为登录状态和非登录状态

    非登录状态:

    登录状态:

    2.实现步骤

    2.1左右两边面板模块:

    左右两边面板模块用bootstarp的栅格系统完成,左2,中8,右2,然后再去copy3个面板,完成

    2.2中间数据的展示:

    后端操作很简单,只需要获取文章表的所有数据发送给前端即可

     article_list=models.Article.objects.all()
        return render(request,'home.html',locals())

    前端代码,把后端发过来的数据,用for循环渲染

    {% for article in article_list %}
                <div class="media">
                    <div class="media-left">
                        <a href="#">
                            <img class="media-object" data-src="holder.js/64x64" alt="64x64"
                                 src="/media/{{ article.blog.userinfo.avatar }}"
                                 data-holder-rendered="true" style=" 64px; height: 64px;">
                        </a>
                    </div>
                    <div class="media-body">
                        <h4 class="media-heading"><a href="/{{ article.blog.userinfo.username }}/{{ article.id }}">{{ article.title }}</a></h4>
                        {{ article.desc }}
                        <div>
                            <span>发布时间:{{ article.create_time }} 点赞数:{{ article.up_num }} 评论数:{{ article.comment_num}}</span>
                        </div>
                    </div>
                </div>
                {% endfor %}

    2.3页面顶部导航栏

    首先实现不同状态下的前端切换,后端是locals()传值,所有request也被传到了前端,那么就可以通过request.user判断用户是否登录

    {% if request.user.is_authenticated %}
    <li><a href="/{{ request.user.username }}/GL">{{ request.user.username }}</a></li>
    <li class="dropdown">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
    aria-expanded="false">更多操作<span class="caret"></span></a>
    <ul class="dropdown-menu">
    <li><a href="/set_password">修改密码</a></li>
    <li><a href="/set_avatar">修改头像</a></li>
    <li role="separator" class="divider"></li>
    <li><a href="/logout">注销</a></li>
    {% else %}
    <li><a href="/login">登录</a></li>
    <li><a href="/register">注册</a></li>
    </ul>
    </li>{% endif %}

    2.3.1非登录状态下

    非登录状态下,给两个a标签添加路径,

     <li><a href="/login">登录</a></li>
                <li><a href="/register">注册</a></li>

    2.3.2 登录状态下,有三个功能,修改密码,修改头像,注销

    修改密码:首先在url文件中添加路径,在views中添加函数,为a标签加上路径,在templates创建一个修改密码页面

    效果如上

    修改密码要有原密码。原密码的是加密的,所以又需要一个函数request.user.check_password()

    验证之后,进行两次新密码的比对,没有问题的话,进行保存,又又又要对密码进行加密,所以需要另外一个函数request.user.set_password(new_password),还有设置完之后别忘记保存request.user.save()

    后端:

    def set_password(request):
        respone_msg={'code':100,'msg':''}
        if request.method=="POST":
            password=request.POST.get('password')
            if request.user.check_password(password):
                new_password=request.POST.get('new_password')
                re_new_password=request.POST.get('re_new_password')
                if new_password==re_new_password:
                    respone_msg['url']='/login'
                    request.user.set_password(new_password)
                    request.user.save()
                    auth.logout(request)
                else:
                    respone_msg['code']=101
                    respone_msg['msg']='两次密码不一致'
            else:
                respone_msg['code'] = 102
                respone_msg['msg'] = '原密码不正确'
            return JsonResponse(respone_msg)
    
        return render(request,'set_password.html',locals())
    修改密码后端源码

    前端:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
    <body>
    <div class="container">
        <h1 class="text-center">修改密码</h1>
        <div class="row">
            <form class="col-lg-offset-3 col-lg-6">
                {% csrf_token %}
                <div class="form-group">
                    <label for="id_username">用户名</label>
                    <input type="text" class="form-control" id="id_username" placeholder="用户名" value={{ request.user.username }} disabled>
                </div>
                <div class="form-group">
                    <label for="id_password">密码</label>
                    <input type="password" class="form-control" id="id_password" placeholder="密码">
                </div>
                 <div class="form-group">
                    <label for="id_password2">新密码</label>
                    <input type="password" class="form-control" id="id_password2" placeholder="密码">
                </div>
                 <div class="form-group">
                    <label for="id_password3">重复新密码</label>
                    <input type="password" class="form-control" id="id_password3" placeholder="密码">
                </div>
    
                <div><input type="button" id="button_id" value="修改" class="btn btn-primary"></div>
                <div> <span id="error" style="color: red"></span></div>
            </form>
        </div>
    </div>
    <script>
        $('#button_id').click(function () {
            $.ajax({
                url:'',
                type:'post',
                data:{
                    'password':$('#id_password').val(),
                    'new_password':$('#id_password2').val(),
                    're_new_password':$('#id_password3').val(),
                    'csrfmiddlewaretoken':$("[name='csrfmiddlewaretoken']").val()
                },
                success:function (data) {
                    if(data.code==100){
                        location.href=data.url
                    }
                    else {
                        $('#error').html(data.msg)
                    }
                }
            })
        })
    </script>
    </body>
    </body>
    </html>
    前端源码

    修改头像:


    头像修改的原理和注册时是一样的,简单不多BB

    def set_avatar(request):
        blog = request.user.blog
        username = request.user.username
        if request.method=="POST":
            file = request.FILES.get('myfile')
            user_obj = models.UserInfo.objects.get(blog=blog)
            user_obj.avatar = file
            user_obj.save()
            return JsonResponse({'url':'/home','code':'100'})
        return render(request,'set_avatar.html',locals())
    后端代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
    <div class="container">
        <div class="row">
            <div class="col-lg-6">
                {% csrf_token %}
                <label for="file_id"> 头像
                    <img data-src="holder.js/140x140" class="img-rounded" alt="140x140" style=" 140px; height: 140px;"
                         src="/media/{{ request.user.avatar }}" data-holder-rendered="true" id="img_id">
                </label>
                <input type="file" id="file_id" class="hidden">
                <p><input type="button" id="button_id" value="修改"></p>
    
            </div>
    
        </div>
    </div>
    <script>
        $('#file_id').change(function () {
            var file = $(this)[0].files[0];
            var read = new FileReader();
            read.readAsDataURL(file);
            read.onload = function () {
                $('#img_id').attr('src', read.result)
            }
        });
        $('#button_id').click(function () {
        var formdata=new FormData();
         formdata.append('myfile',$('#file_id')[0].files[0]);
         formdata.append('csrfmiddlewaretoken',$("[name='csrfmiddlewaretoken']").val());
        $.ajax({
            url:"",
            type:'post',
            data:formdata,
            processData: false,
            contentType: false,
            success:function (data) {
              if(data.code==100){
                location.href=data.url
              }
            }
        })
    })
    </script>
    </body>
    </html>
    前端

    至于最后一个注销就简单了:

    和auth.login相对应的函数,auth.logout

    def logout(request):
        auth.logout(request)
        return redirect('/home')

    首页完整代码:
    后端:
    #首页
    def home(request):
        article_list=models.Article.objects.all()
        return render(request,'home.html',locals())
    #注销
    def logout(request):
        auth.logout(request)
        return redirect('/home')
    #修改密码
    def set_password(request):
        respone_msg={'code':100,'msg':''}
        if request.method=="POST":
            password=request.POST.get('password')
            if request.user.check_password(password):
                new_password=request.POST.get('new_password')
                re_new_password=request.POST.get('re_new_password')
                if new_password==re_new_password:
                    respone_msg['url']='/login'
                    request.user.set_password(new_password)
                    request.user.save()
                    auth.logout(request)
                else:
                    respone_msg['code']=101
                    respone_msg['msg']='两次密码不一致'
            else:
                respone_msg['code'] = 102
                respone_msg['msg'] = '原密码不正确'
            return JsonResponse(respone_msg)
    
        return render(request,'set_password.html',locals())
    #修改头像
    def set_avatar(request):
        blog = request.user.blog
        username = request.user.username
        if request.method=="POST":
            file = request.FILES.get('myfile')
            user_obj = models.UserInfo.objects.get(blog=blog)
            user_obj.avatar = file
            user_obj.save()
            return JsonResponse({'url':'/home','code':'100'})
        return render(request,'set_avatar.html',locals())
    首页后端代码

    前端:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
    <nav class="navbar navbar-inverse">
        <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                        data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">博客园</a>
            </div>
    
            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav">
                </ul>
                <ul class="nav navbar-nav navbar-right">
                    {% if request.user.is_authenticated %}
                        <li><a href="/{{ request.user.username }}/GL">{{ request.user.username }}</a></li>
                        <li class="dropdown">
                            <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                               aria-expanded="false">更多操作<span class="caret"></span></a>
                            <ul class="dropdown-menu">
                                <li><a href="/set_password">修改密码</a></li>
                                <li><a href="/set_avatar">修改头像</a></li>
                                <li role="separator" class="divider"></li>
                                <li><a href="/logout">注销</a></li>
                                {% else %}
                                <li><a href="/login">登录</a></li>
                                <li><a href="/register">注册</a></li>
                            </ul>
                        </li>{% endif %}
                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-2">
                <div class="panel panel-primary">
                    <div class="panel-heading">
                        <h3 class="panel-title">广告位</h3>
                    </div>
                    <div class="panel-body">
                        广告位招租
                    </div>
                    <div class="panel-body">
                        广告位招租
                    </div>
                </div>
                <div class="panel panel-danger">
                    <div class="panel-heading">
                        <h3 class="panel-title">广告位</h3>
                    </div>
                    <div class="panel-body">
                        广告位招租
                    </div>
                    <div class="panel-body">
                        广告位招租
                    </div>
                </div>
                <div class="panel panel-success">
                    <div class="panel-heading">
                        <h3 class="panel-title">广告位</h3>
                    </div>
                    <div class="panel-body">
                        广告位招租
                    </div>
                    <div class="panel-body">
                        广告位招租
                    </div>
                </div>
            </div>
            <div class="col-md-8">
                {% for article in article_list %}
                <div class="media">
                    <div class="media-left">
                        <a href="#">
                            <img class="media-object" data-src="holder.js/64x64" alt="64x64"
                                 src="/media/{{ article.blog.userinfo.avatar }}"
                                 data-holder-rendered="true" style=" 64px; height: 64px;">
                        </a>
                    </div>
                    <div class="media-body">
                        <h4 class="media-heading"><a href="/{{ article.blog.userinfo.username }}/{{ article.id }}">{{ article.title }}</a></h4>
                        {{ article.desc }}
                        <div>
                            <span>发布时间:{{ article.create_time }} 点赞数:{{ article.up_num }} 评论数:{{ article.comment_num}}</span>
                        </div>
                    </div>
                </div>
                {% endfor %}
            </div>
            <div class="col-md-2">
                <div class="panel panel-primary">
                    <div class="panel-heading">
                        <h3 class="panel-title">广告位</h3>
                    </div>
                    <div class="panel-body">
                        广告位招租
                    </div>
                    <div class="panel-body">
                        广告位招租
                    </div>
                </div>
                <div class="panel panel-danger">
                    <div class="panel-heading">
                        <h3 class="panel-title">广告位</h3>
                    </div>
                    <div class="panel-body">
                        广告位招租
                    </div>
                    <div class="panel-body">
                        广告位招租
                    </div>
                </div>
                <div class="panel panel-success">
                    <div class="panel-heading">
                        <h3 class="panel-title">广告位</h3>
                    </div>
                    <div class="panel-body">
                        广告位招租
                    </div>
                    <div class="panel-body">
                        广告位招租
                    </div>
                </div>
            </div>
        </div>
    </div>
    </body>
    </html>
    首页前端
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
    <div class="container">
        <div class="row">
            <div class="col-lg-6">
                {% csrf_token %}
                <label for="file_id"> 头像
                    <img data-src="holder.js/140x140" class="img-rounded" alt="140x140" style=" 140px; height: 140px;"
                         src="/media/{{ request.user.avatar }}" data-holder-rendered="true" id="img_id">
                </label>
                <input type="file" id="file_id" class="hidden">
                <p><input type="button" id="button_id" value="修改"></p>
    
            </div>
    
        </div>
    </div>
    <script>
        $('#file_id').change(function () {
            var file = $(this)[0].files[0];
            var read = new FileReader();
            read.readAsDataURL(file);
            read.onload = function () {
                $('#img_id').attr('src', read.result)
            }
        });
        $('#button_id').click(function () {
        var formdata=new FormData();
         formdata.append('myfile',$('#file_id')[0].files[0]);
         formdata.append('csrfmiddlewaretoken',$("[name='csrfmiddlewaretoken']").val());
        $.ajax({
            url:"",
            type:'post',
            data:formdata,
            processData: false,
            contentType: false,
            success:function (data) {
              if(data.code==100){
                location.href=data.url
              }
            }
        })
    })
    </script>
    </body>
    </html>
    修改头像前端
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
    <body>
    <div class="container">
        <h1 class="text-center">修改密码</h1>
        <div class="row">
            <form class="col-lg-offset-3 col-lg-6">
                {% csrf_token %}
                <div class="form-group">
                    <label for="id_username">用户名</label>
                    <input type="text" class="form-control" id="id_username" placeholder="用户名" value={{ request.user.username }} disabled>
                </div>
                <div class="form-group">
                    <label for="id_password">密码</label>
                    <input type="password" class="form-control" id="id_password" placeholder="密码">
                </div>
                 <div class="form-group">
                    <label for="id_password2">新密码</label>
                    <input type="password" class="form-control" id="id_password2" placeholder="密码">
                </div>
                 <div class="form-group">
                    <label for="id_password3">重复新密码</label>
                    <input type="password" class="form-control" id="id_password3" placeholder="密码">
                </div>
    
                <div><input type="button" id="button_id" value="修改" class="btn btn-primary"></div>
                <div> <span id="error" style="color: red"></span></div>
            </form>
        </div>
    </div>
    <script>
        $('#button_id').click(function () {
            $.ajax({
                url:'',
                type:'post',
                data:{
                    'password':$('#id_password').val(),
                    'new_password':$('#id_password2').val(),
                    're_new_password':$('#id_password3').val(),
                    'csrfmiddlewaretoken':$("[name='csrfmiddlewaretoken']").val()
                },
                success:function (data) {
                    if(data.code==100){
                        location.href=data.url
                    }
                    else {
                        $('#error').html(data.msg)
                    }
                }
            })
        })
    </script>
    </body>
    </body>
    </html>
    修改密码前端
  • 相关阅读:
    JavaScript学习(一)
    CSS学习(1)(网页编程)
    学习MVC3(二)——创建自己的第一个网页:实现用户登陆(1)
    C#多态小结——面向对象编程的三大机制之二
    学习网页编程(一)
    开始的2012
    基于jquery的上传插件Uploadify 3.1.1在MVC3中的使用:上传大文件的IO Error问题
    网页编程注意
    基于jquery的上传插件Uploadify 3.1.1在MVC3中的使用
    BackgroundSize
  • 原文地址:https://www.cnblogs.com/98WDJ/p/10817840.html
Copyright © 2020-2023  润新知