BBS 登录

目录

上周内容

bbs项目
    
    
    项目开发流程
        需求分析
        
        架构设计
        
        分组开发
            我们一般情况下都只是作用于这一步
        
        各项测试

        交付上线
            
    bbs表设计
        任何一个项目 最最重要的部分都是数据库的表设计
    
    用户表
        继承AbstractUser表  来做额外的字段扩展
            1.类的继承
            2.配置文件配置
                AUTH_USER_MODEL = '应用名.类名'
        
        phone
        avatar
            upload_to='avatar/'
        register_time
        
        
        
    
    个人站点表
        站点标题
        站点名称
        站点样式
            模拟
        
    
    文章标签表
        标签名称
    
    文章分类表
        分类名称
    
    文章表
        文章标题
        文章简介
        文章内容
        文章日期
        
        # 数据库优化字段
        点赞数
        点踩数
        评论数
        
    
    点赞点踩表
        用户id         一对多字段
        文章id           一对多字段
        点赞点踩        1/0
        
    
    评论表
        用户id            一对多字段
        文章id            一对多字段
        评论内容
        评论时间
        自关联字段       自己跟自己所在的表关联
        
    
    数据库配置
        1.配置文件
        2.__init__文件
    
    数据库迁移命令
        python3 manage.py makemigrations    
        python3 manage.py migrate
    
    注册功能
        只要是注册功能一般都有一定的校验规则
        
        我们利用forms组件 来完成注册的校验
            用户名
                label
                error_messages
                    required
                    invalid
                widget
                validators
            密码
            确认密码
            邮箱
            
            钩子函数
                校验用户名是否已存在
            
                校验两次密码是否一致
        
        一旦你的项目特别庞大 需要用到很多forms组件 
        那么你可以单独的将所有forms组件放到一个py文件中或者一个文件下
        然后针对不同的功能开设不同的py文件
            单独的py文件
        
            文件夹
                1.py
                2.py
                3.py
                4.py
            
    注册功能使用的是ajax做后端交互
    但是我们用的了form标签
        因为form标签有一个自动序列化普通键值对的功能
        可以方便的将普通键值对循环添加到formdata对象中
    
    label标签在跟input有绑定关系的前提下
    内部无论放什么对象 点击都能够是对应的input框聚焦
    
    img标签src属性可以放的值
        1.图片的地址
        2.图片的二进制数据
        3.后端url   自动朝该url发送get请求
    
    实时展示用户选择的头像
        利用内置对象fileReader
            文件阅读器在读取文件的时候 是一个异步io操作
            所以你在渲染img标签的时候一定要等待文件阅读器加载完毕之后再渲染
            等待...加载完毕
                onload
                window.onload = function(){}
                fileReader.onload = function(){}
    发送ajax请求
        1.ajax提交数据基本语法
        2.ajax发送文件需要借助于内置对象formdata
            ajax发送formdata对象
            需要制定两个参数都为false
                processData
                contentType
    后端正常的业务逻辑无需多说
    
    
    一旦报错之后前端如何对应的渲染相应的信息
        1.你需要研究form组件渲染的input框的id值的特点
            id_字段名
        2.你又发现返回的报错信息 键就是一个个的字段名
            自己手动拼接处input框的id值
            然后利用DOM操作 来操作span标签以及div标签
    
    最后为了功能的健壮性
        给所有的input设置获取焦点事件
            自动移除报错信息和报错的样式
        
    
    控制字体样式的文件都是以.ttf结尾
    
    
    
    
本周
    bbs结束

今日内容
    登录功能
    
    首页搭建
    
    导航条用户功能
    
    admin后台管理

下周安排(15d~22d)
    vue前端框架   3~5d
    django restframework(******)
    路飞项目
    git
    celery
    项目上线

今日内容

url.py

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 注册功能
    url(r'^register/',views.register,name='register'),
    # 登录功能
    url(r'^login/',views.login,name='login'),
    # 验证码图片
    url(r'^get_code/',views.get_code,name='code'),
    # 首页搭建
    url(r'^home/',views.home,name='home'),
    # 退出登录
    url(r'^logout/',views.logout,name='logout'),
    # 修改密码
    url(r'^set_password/',views.set_password,name='set_pwd')
]

views.py

from django.shortcuts import render,HttpResponse,redirect,reverse
from app01 import  myform
from app01 import  models
from django.http import JsonResponse
# 验证码相关
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO, StringIO
# auth模块校验密码
from django.contrib import auth
from django.contrib.auth.decorators import login_required

# Create your views here.
def register(request):
    # 生成一个空的forms对象
    form_obj = myform.MyRegForm()

    if request.method == 'POST':
        back_dic = {'code':1000,'msg':''}

        # 对用户提交的数据先进行校验 forms
            # 直接使用forms组件的校验方法,校验整个的数据字典
        form_obj = myform.MyRegForm(request.POST)
        if form_obj.is_valid():
            # 如果数据校验结果正确
            clean_data = form_obj.cleaned_data   # 获取正确的数据 4个键值对
            # 将确认密码的键值对弹出,只剩余三个便于创建用户
            clean_data.pop('confirm_password')
            # 获取用户上传的文件
            file_obj = request.FILES.get('avatar')
            # 判断文件是否存在,用户是否上传,如果没有上传才会设置default头像
            if file_obj:
                clean_data['avatar'] = file_obj     # 四个键值对
            # 自动创建,使用**直接打散关键字参数
            models.Userinfo.objects.create_user(**clean_data)
            # 添加成功界面信息,及跳转
            back_dic['msg'] = '注册成功'
            back_dic['url'] = '/login/'
        else:
            back_dic['code'] = 2000
            # 将错误信息返回给前端
            back_dic['msg'] = form_obj.errors
        # 返回给前端字典
        return JsonResponse(back_dic)
    return render(request,'register.html',locals())



# 登录功能
def login(request):
    if request.method == 'POST':
        back_dic = {'code':1000,'msg':''}
        username = request.POST.get('username')
        password = request.POST.get('password')
        code = request.POST.get('code')
        # 1.先校验验证码是否正确 忽略大小写
        if request.session.get('code').upper() == code.upper():
            # 2.校验用户名密码是否正确 利用auth模块
            user_obj = auth.authenticate(request,username=username,password=password)
            if user_obj:
                # 3.保存用户登录状态
                auth.login(request,user_obj)
# 就可以在任意位置通过request.user获取到当前登录对象 并且 request.user.is_authenticated()判断当前用户是否登录
                # 返回前端信息,并定向主页
                back_dic['msg'] = '登录成功'
                back_dic['url'] = '/home/'
            else:
                back_dic['code'] = 2000
                back_dic['msg'] = '用户名或密码错误'
        else:
            back_dic['code'] = 3000
            back_dic['msg'] = '验证错误'
        # 返回给前端字典数据
        return JsonResponse(back_dic)
    return render(request,'login.html')


import random
# 给验证码的图片添加随机颜色
def get_random():
    return random.randint(0,255),random.randint(0,255),random.randint(0,255)


# 图片验证码相关
def get_code(request):
    # 推导步骤一:直接发送后端存在的图片
        # img标签可以直接返回二进制数据进行显示
    # with open(r'static/img/02b02.jpg.jpg','rb') as f:
    #     data = f.read()
    # return HttpResponse(data)

    # 推导步骤二 利用pillow模块自动生成图片
    '''
    from PIL import Image,ImageDraw,ImageFont
    Image       生成图片
    ImageDraw   在图片上写字
    ImageFont   控制字体的样式'''
    # 生成图片对象
    # img_obj = Image.new('RGB',(360,35),'red')     直接放文件的颜色
    # img_obj = Image.new('RGB',(360,35),get_random())   # 放rgb模式(255,23,232)
    # # 利用文件操作先保存下来
    # with open('xxx.png','wb') as f:
    #     img_obj.save(f,'png')
    # # 然后利用文件操作将图片数据读取并发送
    # with open(r'xxx.png','rb') as f:
    #     data = f.read()
    # return HttpResponse(data)

    # 推导步骤三  临时存储数据并且能够随时取出的地方
    '''内存管理模块
    from io import BytesIO,StringIO
    BytesIO     保存数据(并且在获取的时候,是以二进制的方式给你)
    StringIO    保存数据(以字符串的形式给你)
    '''
    # img_obj = Image.new('RGB',(360,35),get_random())
    #     # # 先生成一个io对象
    #     # io_obj = BytesIO()    # 可以将对象当做是文件的句柄
    #     # # 存储数据
    #     # img_obj.save(io_obj,'png')
    #     # # getvalue获取二进制的数据
    #     # return HttpResponse(io_obj.getvalue())

    # 推导步骤四     在图片上写字
    img_obj = Image.new('RGB',(360,35),get_random())
    # 将生成好的图片对象交给imageDraw
    img_draw = ImageDraw.Draw(img_obj)  # 生成一个画笔对象
    # 字体样式,将ttf格式字体,及字体的大小 设置
    img_font = ImageFont.truetype('static/fonts/1.ttf',30)
    # 产生一个随机验证码  大小写英文加数字 五位,每一位都可以是大小写数据
    code= ''
    for i in range(5):
        # chr 根据数字对应字符编码的英文
        upper_str = chr(random.randint(65,90))
        lower_str = chr(random.randint(97,122))
        random_int = str(random.randint(0,9))
        # 随机选取一个字符
        tmp = random.choice([upper_str,random_int,lower_str])
        # 向图片中写入一个((x轴,y轴)坐标,文本,图片北京,字体样式)
        img_draw.text((i*60+60,0),tmp,get_random(),img_font)
        # 存储写的字
        code += tmp
    print(code)
    # 这个验证码后面的其他视图函可能用得上,找到地方保存,并且这个地方的全局视图函数都可以访问
    request.session['code'] = code
    # 图片保存
    io_obj = BytesIO()
    img_obj.save(io_obj,'png')
    return HttpResponse(io_obj.getvalue())


# 首页的搭建
def home(request):
    return render(request,'home.html',locals())


# 退出登录
@login_required
def logout(request):
    # 退出登录
    auth.logout(request)
    # 重定向到主页
    return redirect(reverse('home'))


@login_required
def set_password(request):
    if request.method == 'POST':
        old_pwd = request.POST.get('old_password')
        new_pwd = request.POST.get('new_password')
        confirm_password = request.POST.get('confirm_password')
        # 1.先判断旧密码是否正确
        is_right = request.user.check_password(old_pwd)
        if is_right:
            # 判断新密码与确认密码是否一致
            if new_pwd == confirm_password:
                # 修改密码
                request.user.set_password(new_pwd)
                request.user.save()
                # 重定向界面
                return redirect(reverse('login'))
            else:
                return HttpResponse('两次密码不一致')
        else:
            return HttpResponse('原密码不正确')

login

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>

</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2 ">
            <h2 class="text-center">登录界面</h2>
            <div class="form-group">
                <label for="id_username">用户名</label>
                <input type="text" name="username" id="id_username" class="form-control">
            </div>
            <div class="form-group">
                <label for="id_password">密码</label>
                <input type="password" name="password" id="id_password" class="form-control">
            </div>
{#            验证码框#}
            <div class="form-group">
                <label for="id_code">验证码</label>
                <div class="row">
                    <div class="col-md-6">
                        <input type="text" name="code" id="id_code" class="form-control">
                    </div>
                    <div class="col-md-6">
                        <img src="/get_code/" alt="" width="360" height="35" id="id_img">
                    </div>
                </div>
            </div>
            <input type="button" class="btn btn-primary" value="登录" id="id_submit">
{#            // 错误信息的展示#}
            <span style="color: red;" id="id_error"></span>
        </div>
    </div>
</div>

<script>
    {#绑定验证码点击刷新事件#}
    $('#id_img').click(function () {
        var oldPath = $(this).attr('src');
        $(this).attr('src',oldPath+='?')
    });

    {#发送ajax请求与后端交互#}
    $('#id_submit').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data:{
                'username':$('#id_username').val(),
                'password':$('#id_password').val(),
                'code':$('#id_code').val(),
                'csrfmiddlewaretoken':'{{ csrf_token }}'
            },
            {#进行处理后端数据#}
            success:function (data) {
                if(data.code==1000){
                    // 验证成功则跳转主页
                    window.location.href = data.url
                }else {  // 报错信息的展示
                    $('#id_error').text(data.msg)
                }
            }
        })
    })

</script>
</body>
</html>

home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.3.7-dist/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="/home/">BBS首页系统</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">
        <li class="active"><a href="#">文章 <span class="sr-only">(current)</span></a></li>
        <li><a href="#">随笔</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="#">Action</a></li>
            <li><a href="#">Another action</a></li>
            <li><a href="#">Something else here</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">Separated link</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">One more separated link</a></li>
          </ul>
        </li>
      </ul>
      <form class="navbar-form navbar-left">
        <div class="form-group">
          <input type="text" class="form-control" placeholder="Search">
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
      </form>
      <ul class="nav navbar-nav navbar-right">
{#     判断用户是否登录  显示登录注册按钮#}
          {% if request.user.is_authenticated %}
{#              根据后端,显示登录之后的按钮#}
                <li><a href="#">{{ 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">
{#               添加模态框的属性data-toggle="modal" data-target="#myModal"#}
                    <li><a data-toggle="modal" data-target="#myModal">修改密码</a></li>
                    <li><a href="#">修改头像</a></li>
                    <li><a href="#">后台管理</a></li>
                    <li role="separator" class="divider"></li>
                    <li><a href="{% url 'logout' %}">退出登录</a></li>
                  </ul>
                </li>
              {% else %}
{#              没有登录则显示登录注册按钮#}
                <li><a href="{% url 'login' %}">登录</a></li>
                <li><a href="{% url 'register' %}">注册</a></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">
                劳斯莱斯5元代金券
              </div>
            </div>
            <div class="panel panel-danger">
              <div class="panel-heading">
                <h3 class="panel-title">限定优惠</h3>
              </div>
              <div class="panel-body">
                割双眼皮买二送一
              </div>
            </div>
            <div class="panel panel-warning">
              <div class="panel-heading">
                <h3 class="panel-title">最后换购</h3>
              </div>
              <div class="panel-body">
                买电烤炉送蜂窝煤一斤!
              </div>
            </div>
        </div>
{# 中间面板 #}
        <div class="col-md-8"></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">
                劳斯莱斯5元代金券
              </div>
            </div>
            <div class="panel panel-danger">
              <div class="panel-heading">
                <h3 class="panel-title">限定优惠</h3>
              </div>
              <div class="panel-body">
                割双眼皮买二送一
              </div>
            </div>
            <div class="panel panel-warning">
              <div class="panel-heading">
                <h3 class="panel-title">最后换购</h3>
              </div>
              <div class="panel-body">
                买电烤炉送蜂窝煤一斤!
              </div>
            </div>
        </div>
    </div>
</div>

{#修改密码的弹出框#}
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="myModalLabel">修改密码</h4>
      </div>
      <div class="modal-body">
{#          设置密码的更改#}
          <form action="{% url 'set_pwd' %}" method="post">
              {% csrf_token %}
              <div class="form-group">
                  <label for="id_username">用户名</label>
                  <input type="text" id="id_username" name="username" disabled class="form-control" value="{{ request.user.username }}">
              </div>
              <div class="form-group">
                  <label for="id_password">初始密码</label>
                  <input type="password" id="id_password" name="old_password" class="form-control" >
              </div>
              <div class="form-group">
                  <label for="id_new_password">新密码</label>
                  <input type="password" id="id_new_password" name="new_password" class="form-control" >
              </div>
              <div class="form-group">
                  <label for="id_confirm_password">确认新密码</label>
                  <input type="password" id="id_confirm_password" name="confirm_password" class="form-control">
              </div>

             <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
                <button class="btn btn-primary" id="id_s">提交</button>
              </div>
          </form>
      </div>
    </div>
  </div>
</div>

</body>
</html>

逻辑流程

登录功能

1.定义登录界面

2.添加验证码的功能

    图片验证码的传值有三种方式,直接写地址,文件二进制数据,路径
    验证码的实现
        通过Image获取imgobj对象
        生成好的img对象交给ImageDraw.Draw 生成画笔
        定义字体样式,文字大小
        产生随机的验证码,利用chr实现,(65,96)大写,(97,122)小写,数字直接就是0-9
        随机5个数字,在每个循环里写入
        利用画笔对象.text((x轴,y轴)坐标,文本,图片北京,字体样式)
        存储写的字
    保存到session中的code
    然后保存图片io
    最终返回给前端值  return HttpResponse(io_obj.getvalue())
    
3.给验证码绑定点击事件
    每点击一次url添加一个?用于刷新
    
4.使用ajax与后端进行交互
    将用户的输入获取到手
    success回调函数拿到后端返回的数据
    根据code的信信息对相关标签进行渲染
    后端得到数据进行验证
        先判断验证码是否正确
        然后利用auth模块判断密码是否正确
        根据得到对象判断存在
            定义返回字典,返回给前端
            return JsonResponse(back_dic)

验证码相关推导

def get_code(request):
    # 推导步骤一:直接发送后端存在的图片
        # img标签可以直接返回二进制数据进行显示
    # with open(r'static/img/02b02.jpg.jpg','rb') as f:
    #     data = f.read()
    # return HttpResponse(data)




    # 推导步骤二 利用pillow模块自动生成图片
    '''
    from PIL import Image,ImageDraw,ImageFont
    Image       生成图片
    ImageDraw   在图片上写字
    ImageFont   控制字体的样式'''
    # 生成图片对象
    # img_obj = Image.new('RGB',(360,35),'red')     直接放文件的颜色
    # img_obj = Image.new('RGB',(360,35),get_random())   # 放rgb模式(255,23,232)
    # # 利用文件操作先保存下来
    # with open('xxx.png','wb') as f:
    #     img_obj.save(f,'png')
    # # 然后利用文件操作将图片数据读取并发送
    # with open(r'xxx.png','rb') as f:
    #     data = f.read()
    # return HttpResponse(data)





    # 推导步骤三  临时存储数据并且能够随时取出的地方
    '''内存管理模块
    from io import BytesIO,StringIO
    BytesIO     保存数据(并且在获取的时候,是以二进制的方式给你)
    StringIO    保存数据(以字符串的形式给你)
    '''
    # img_obj = Image.new('RGB',(360,35),get_random())
    #     # # 先生成一个io对象
    #     # io_obj = BytesIO()    # 可以将对象当做是文件的句柄
    #     # # 存储数据
    #     # img_obj.save(io_obj,'png')
    #     # # getvalue获取二进制的数据
    #     # return HttpResponse(io_obj.getvalue())






    # 推导步骤四     在图片上写字
    
    img_obj = Image.new('RGB',(360,35),get_random())
    # 将生成好的图片对象交给imageDraw
    img_draw = ImageDraw.Draw(img_obj)  # 生成一个画笔对象
    # 字体样式,将ttf格式字体,及字体的大小 设置
    img_font = ImageFont.truetype('static/fonts/1.ttf',30)
    # 产生一个随机验证码  大小写英文加数字 五位,每一位都可以是大小写数据
    code= ''
    for i in range(5):
        # chr 根据数字对应字符编码的英文
        upper_str = chr(random.randint(65,90))
        lower_str = chr(random.randint(97,122))
        random_int = str(random.randint(0,9))
        # 随机选取一个字符
        tmp = random.choice([upper_str,random_int,lower_str])
        # 向图片中写入一个((x轴,y轴)坐标,文本,图片北京,字体样式)
        img_draw.text((i*60+60,0),tmp,get_random(),img_font)
        # 存储写的字
        code += tmp
    print(code)
    # 这个验证码后面的其他视图函可能用得上,找到地方保存,并且这个地方的全局视图函数都可以访问
    request.session['code'] = code
    # 图片保存
    io_obj = BytesIO()
    img_obj.save(io_obj,'png')
    return HttpResponse(io_obj.getvalue())

猜你喜欢

转载自www.cnblogs.com/fwzzz/p/12016591.html
bbs