仿bbs项目之登录补充,首页,后台,个人站点

仿bbs项目之登录补充,首页,后台,个人站点

今日内容概要

  • 登录功能补充编写
  • 首页导航条样式
  • 修改密码与注销登录
  • admin后台管理简介
  • 后台数据绑定
  • 首页样式搭建
  • media媒体目录
  • 图片防盗链技术
  • 个人站点页面搭建
  • 个人站点侧边栏展示

今日内容详细

登录功能补充编写

    # 5.推导步骤5:编写验证码
    # 先产生图片对象
    img_obj = Image.new('RGB', (350, 35), get_random())
    # 将图片对象交给画笔对象
    draw_obj = ImageDraw.Draw(img_obj)
    # 确定字体样式(ttf文件)
    font_obj = ImageFont.truetype('static/font/111.ttf', 35)
    # 产生一个随机验证码
    code = ''
    for i in range(5):
        random_upper = chr(random.randint(65, 90))
        random_lower = chr(random.randint(97, 122))
        random_int = str(random.randint(1, 9))
        # 三选一
        temp_choice = random.choice([random_upper, random_lower, random_int])
        # 写到图片上
        draw_obj.text((i*60+45, 0), temp_choice, font=font_obj)
        code += temp_choice
    # 后端保存验证码 便于后续的比对
    request.session['code'] = code
    io_obj = BytesIO()
    img_obj.save(io_obj, 'png')
    return HttpResponse(io_obj.getvalue())

前端验证码动态刷新和发送ajax请求
    <script>
        // 1.验证码动态刷新
        $('#d1').click(function () {
            let oldSrc = $(this).attr('src');
            $(this).attr('src', oldSrc + '?')
        })

        // 2,登录按钮发送ajax请求
        $('#loginBtn').click(function () {
            // 可以再次使用form标签序列化功能 也可以自己获取
            {#console.log($('#myform').serializeArray())  // [{},{},{},{}] ajax不太好用form,所以不用了#}
            $.ajax({
                url:'',
                type:'post',
                data:{'username': $('#name').val(), 'password': $('#password').val(), 'code': $('#code').val(), 'csrfmiddlewaretoken': '{{ csrf_token }}'},
                success: function (args) {
                    if(args.code === 10000){
                        window.location.href = args.url
                    }else {
                        // 课下可以使用sweetalert插件美化展示
                        {#alert(args.msg)#}
                        swal(args.msg, 'error')
                    }
                }
            })
        })
    </script>

后端接收数据并与前端交互
def login_func(request):
    back_dict = {'code': 10000, 'msg': ''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        code = request.POST.get('code')
        if code.upper() == request.session.get('code').upper():
            res = auth.authenticate(request, username=username, password=password)
            if res:
                back_dict['msg'] = '登录成功'
                back_dict['url'] = '/home/'
            else:
                back_dict['msg'] = '用户名或密码错误'
                back_dict['code'] = 10001
        else:
            back_dict['code'] = 10002
            back_dict['msg'] = '验证码错误'
        return JsonResponse(back_dict)

    return render(request, 'loginPage.html')

首页导航条样式

1.复制导航条,并进行微调
{% if request.user.is_authenticated %}  <!--is_authenticated判断当前用户是登录用户还是匿名用户,返回T or F-->
                <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">
                    <li><a href="#">修改密码</a></li>
                    <li><a href="#">修改头像</a></li>
                    <li><a href="#">后台管理</a></li>
                    <li role="separator" class="divider"></li>
                    <li><a href="#">退出登录</a></li>
                  </ul>
                </li>
            {% else %}
                <li><a href="{% url 'login_view' %}">登录</a></li>
                <li><a href="{% url 'register_view' %}">注册</a></li>
            {% endif %}
2.登录方面补充完整,保存用户登录状态
auth.login(request, user_obj)  # 执行之后就可以使用request.user获取登录用户对象
3.view简单返回页面,传入数据
def home_func(request):
    return render(request, 'homePage.html', locals())

修改密码与注销登录

<li><a href="#" data-toggle="modal" data-target="#myModal">修改密码</a></li>

<li><a href="/logout/">退出登录</a></li>


<!--模态框开始-->
<!-- Button trigger modal -->


<!-- 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">
          <div class="form-group">
              <label for="">用户名</label>
              <input type="text" value="{{ request.user.username }}" disabled class="form-control">
          </div>
          <div class="form-group">
              <label for="">原密码</label>
              <input type="password" class="form-control" id="old_pwd">
          </div>
          <div class="form-group">
              <label for="">新密码</label>
              <input type="password" class="form-control" id="new_pwd">
          </div>
          <div class="form-group">
              <label for="">确认密码</label>
              <input type="password" class="form-control" id="confirm_pwd">
          </div>
      </div>
      <div class="modal-footer">
          <span id="error" style="color: red"></span>
        <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
        <button type="button" class="btn btn-warning" id="setBtn">确认修改</button>
      </div>
    </div>
  </div>
</div>
<!--模态框结束-->

<script>
    $('#setBtn').click(function () {
        $.ajax({
            url:'/set_pwd/',
            type:'post',
            data: {
                'old_pwd': $('#old_pwd').val(),
                'new_pwd': $('#new_pwd').val(),
                'confirm_pwd': $('#confirm_pwd').val(),
                'csrfmiddlewaretoken': '{{ csrf_token }}',
            },
            success:function (args) {
                if(args.code === 10000){
                    window.location.href = args.url
                }else {
                    $('#error').text(args.msg)
                }

            }
        })
    })
</script>
@login_required
def set_pwd_func(request):
    back_dict = {'code': 10000, 'msg': ''}
    if request.method == 'POST':
        old_pwd = request.POST.get('old_pwd')
        new_pwd = request.POST.get('new_pwd')
        confirm_pwd = request.POST.get('confirm_pwd')
        # 先校验原密码是否正确
        if request.user.check_password(old_pwd):
            # 再校验两次密码是否一致并且不能为空
            if new_pwd == confirm_pwd and new_pwd:
                request.user.set_password(new_pwd)
                request.user.save()
                back_dict['msg'] = '密码修改成功'
                back_dict['url'] = '/login/'
            else:
                back_dict['code'] = 10001
                back_dict['msg'] = '两次密码不一致或者为空'
        else:
            back_dict['code'] = 10002
            back_dict['msg'] = '原密码错误'
        return JsonResponse(back_dict)


@login_required
def logout_func(request):
    auth.logout(request)
    return redirect('home_view')

admin后台管理简介

from django.contrib import admin
from app01 import models
# Register your models here.

"""只要注册了 admin就会产生针对该注册表的增删改查至少四个功能"""
admin.site.register(models.UserInfo)
admin.site.register(models.Site)
admin.site.register(models.Article)
admin.site.register(models.Category)
admin.site.register(models.Tag)
admin.site.register(models.Article2Tag)
admin.site.register(models.UpAndDown)
admin.site.register(models.Comment)

后台管理数据绑定

    # 修改admin后台管理的表名
    class Meta:
        verbose_name_plural = '用户表'

    def __str__(self):
        return f'用户对象:{self.username}'
    
    创建表的数据,不要忘记用户表的绑定

    
'''phone = models.BigIntegerField(verbose_name='手机号', null=True, blank=True)  # blank=True用于控制后台管理与数据库无关'''

首页样式搭建

新建mypage.py内复制分页器代码


def home_func(request):
    # 查询所有用户编写的文章
    article_queryset = models.Article.objects.all()
    '''文章过多的情况下应该考虑添加分页器'''
    page_obj = myPage.Pagination(current_page=request.GET.get('page'), all_count=article_queryset.count())
    page_queryset = article_queryset[page_obj.start:page_obj.end]

    return render(request, 'homePage.html', locals())

---------------------------------------------------------------

        <div class="col-md-8">
            {% for article_obj in page_queryset %}
                <div class="media">
                <h4 class="media-heading"><a href="#">{{ article_obj.title }}</a></h4>
                  <div class="media-left">
                    <a href="#">
                      <img class="media-object" src="/static/img/default.jpg" alt="..." width="80">
                    </a>
                  </div>
                  <div class="media-body">
                    {{ article_obj.desc }}
                  </div>
                    <br>
                    <span><a href="#">{{ article_obj.site.userinfo.username }}&nbsp;&nbsp;</a></span>
                    <span>{{ article_obj.create_time|date:'Y-m-d H:i:s' }}&nbsp;&nbsp;</span>
                    <span class="glyphicon glyphicon-thumbs-up">{{ article_obj.up_num }}&nbsp;&nbsp;</span>
                    <span class="glyphicon glyphicon-thumbs-down">{{ article_obj.down_num }}&nbsp;&nbsp;</span>
                    <span class="glyphicon glyphicon-comment">{{ article_obj.comment_num }}&nbsp;&nbsp;</span>
                </div>
                <hr>
            {% endfor %}
            <div class="text-center">{{ page_obj.page_html|safe }}</div>

media媒体目录

# 以后用户上传的头像 媒体文件都会自动保存到该路径下
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

src="/media/{{ article_obj.site.userinfo.avatar }}/"


from django.views.static import serve
from django.conf import settings

    # 自定义暴露资源接口
    re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
    '''可以暴露任何你想暴露的文件路径,慎重使用'''

图片防盗链技术

    # 个人站点
    path('<str:username>/', views.site_func, name='site_view')
    
    def site_func(request, username):
    # 查询个人站点是否存在
    site_obj = models.Site.objects.filter(site_name=username)
    if not site_obj:
        return render(request, 'errorPage.html')
    return HttpResponse(username)
'''动态匹配用户名的网址'''

个人站点页面搭建

{% extends 'homePage.html' %}

{% block css %}
    <link rel="stylesheet" href="media/css/{{ site_obj.site_theme }}/">
{% endblock %}

{% block title %}
    {{ site_obj.site_title }}
{% endblock %}

{% block myhtml %}
        <div class="col-md-2">
            <ul class="list-group">
              <li class="list-group-item list-group-item-success">文章分类</li>
              <li class="list-group-item list-group-item-info">文章标签</li>
              <li class="list-group-item list-group-item-warning">日期归档</li>
              <li class="list-group-item list-group-item-danger">联系电话:12345</li>
            </ul>
            <div class="list-group">
              <a href="#" class="list-group-item list-group-item-success">阳痿求助</a>
              <a href="#" class="list-group-item list-group-item-info">必有重谢</a>
              <a href="#" class="list-group-item list-group-item-warning">联系人:ahong321</a>
              <a href="#" class="list-group-item list-group-item-danger">联系电话:54321</a>
            </div>
        </div>
        <div class="col-md-10">
        {% for article_obj in article_queryset %}
            <div class="media">
                <h4 class="media-heading"><a href="#">{{ article_obj.title }}</a></h4>
                  <div class="media-body">
                    {{ article_obj.desc }}
                  </div>
                    <br>
                <div class="pull-right">
                    <span>posted;&nbsp;&nbsp;@</span>
                    <span>{{ article_obj.create_time|date:'Y-m-d H:i:s' }}&nbsp;&nbsp;</span>
                    <span><a href="/{{ article_obj.site.userinfo.username }}/">{{ article_obj.site.userinfo.username }}&nbsp;&nbsp;</a></span>
                    <span class="glyphicon glyphicon-thumbs-up">{{ article_obj.up_num }}&nbsp;&nbsp;</span>
                    <span class="glyphicon glyphicon-thumbs-down">{{ article_obj.down_num }}&nbsp;&nbsp;</span>
                    <span class="glyphicon glyphicon-comment">{{ article_obj.comment_num }}&nbsp;&nbsp;</span>
                </div>


                </div>

        {% endfor %}
        <div class="text-center">{{ page_obj.page_html|safe }}</div>

        </div>
{% endblock %}
    # 个人站点
    path('<str:username>/', views.site_func, name='site_view')



def site_func(request, username):
    # 查询个人站点是否存在
    site_obj = models.Site.objects.filter(site_name=username).first()
    if not site_obj:
        return render(request, 'errorPage.html')
    # 查询个人站点下所有的文章
    article_queryset = models.Article.objects.filter(site=site_obj)

    '''文章过多的情况下应该考虑添加分页器'''
    page_obj = myPage.Pagination(current_page=request.GET.get('page'), all_count=article_queryset.count())
    page_queryset = article_queryset[page_obj.start:page_obj.end]

    return render(request, 'sitePage.html', locals())

个人站点侧边栏展示

from django.db.models import Avg, Count, Sum, Min, Max


    # 查询个人站点下所有的分类名称以及每个分类下的文章数
    category_queryset = models.Category.objects.filter(site=site_obj).annotate(article_num=Count('article__pk')).values(
        'name', 'article_num'
    )
    # print(category_queryset)  # <QuerySet [{'name': 'tony的分类1', 'article_num': 1}, {'name': 'tony的分类2', 'article_num
    # ': 2}, {'name': 'tony的分类3', 'article_num': 2}]>
    # 查询个人站点下所有的标签名称以及每个标签下的文章数
    tag_queryset = models.Tag.objects.filter(site=site_obj).annotate(article_num=Count('article__pk')).values(
        'name', 'article_num'
    )
    # 年月分组并统计文章个数
    from django.db.models.functions import TruncMonth
    date_queryset = models.Article.objects.filter(site=site_obj).annotate(month=TruncMonth('create_time')).values('month').annotate(
        article_num=Count('pk')).values('month', 'article_num')
        <div class="col-md-2">
            <div class="panel panel-primary">
                  <div class="panel-heading">
                    <h3 class="panel-title">文章分类</h3>
                  </div>
                  <div class="panel-body">
                        {% for category_obj in category_queryset %}
                            <p><a href="#">{{ category_obj.name }}({{ category_obj.article_num }})</a></p>
                        {% endfor %}
                  </div>
                </div>
                    <div class="panel panel-warning">
                  <div class="panel-heading">
                    <h3 class="panel-title">文章标签</h3>
                  </div>
                  <div class="panel-body">
                        {% for tag_obj in tag_queryset %}
                            <p><a href="#">{{ tag_obj.name }}({{ tag_obj.article_num }})</a></p>
                        {% endfor %}
                  </div>
                </div>
            <div class="panel panel-danger">
                  <div class="panel-heading">
                    <h3 class="panel-title">日期归档</h3>
                  </div>
                  <div class="panel-body">
                        {% for date_obj in date_queryset %}
                            <p><a href="#">{{ date_obj.month|date:'Y年m月' }}({{ date_obj.article_num }})</a></p>
                        {% endfor %}
                  </div>
                </div>
        </div>

posted @ 2023-01-03 23:26  lsumin  阅读(39)  评论(1)    收藏  举报