BBS-博客首页

重点功能:

  • 修改密码弹出模态框
  • 展示出所有文章
  • 文章旁边可以显示作者头像

一、添加路由

在urls.py中添加,

导入模块

from django.conf.urls import url
from django.contrib import admin
from app01 import views

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

1、首页路由

    # 首页相关
    url(r'^home/$', views.home),  # 首页路由

2、修改密码路由

    url(r'^set_password/$', views.set_password),  # 修改密码路由

3、退出登录路由

    url(r'^logout/$', views.logout),  # 退出登录路由

4、个人头像路由

    # 如果你想访问media文件夹下的内容,必须开设一个接口对外访问
    url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),

首页

首页前端

首页前端步骤

总步骤:

1.导航条
登录和未登录导航栏右边是两种形式,加个判断
    {% if  request.session.username %}
    <!-- 动态获取用户名 -->
    {% else %}
    注册登录两个标签
    {% endif %}
2.剩下布局分成3份:2,8,2
3.左右两边先用面板占位置
4.中间是文章内容,复制媒体对象先用文字和默认图片调整好样式
5.首页数据展示
6.图片上传到media文件夹中,配置上传路径(settings中配置路径),增加访问media接口(路由配置)

首页前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>BBS仿博客园搭建</title>
    {#    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css">#}
    {#    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>#}
    {#    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css"></script>#}
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'js/jquery.min.js' %}"></script>
    <script src="{% static 'bootstrap-3.4.1-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="#">仿博客园作业(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="#">专区</a></li>
                        <li><a href="#">闪存</a></li>
                        <li><a href="#">班级</a></li>
                        <li role="separator" class="divider"></li>
                        <li><a href="#">怀旧</a></li>
                        <li role="separator" class="divider"></li>
                        <li><a href="#">发现</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">搜索</button>
            </form>
            <ul class="nav navbar-nav navbar-right">
                {% if  request.session.username %} <!-- 用户登录显示用户名,失败显示注册登录样式 -->
                    <li><a href="#">{{ request.session.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="#" data-toggle="modal" data-target=".bs-example-modal-lg">修改密码</a></li>
                            <li><a href="#">后台管理</a></li>
                            <li><a href="/logout/">退出登录</a></li>
                        </ul>
                    </li>
                {% else %}
                    <li><a href="/register/">注册</a></li><!-- 点击注册跳转到注册页面 -->
                    <li><a href="/login/">登录</a></li>
                {% endif %}
            </ul>

            {# 修改密码开始 #}
            <div><!-- 点击修改密码,弹出模态框 -->
                <div class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog"
                     aria-labelledby="myLargeModalLabel">
                    <div class="modal-dialog modal-lg" role="document">
                        <div class="modal-content">
                            <h1 class="text-center">修改密码</h1>
                            <div class="row">
                                <div class="col-md-8 col-md-offset-2">
                                    <form action="">
                                        <div class="form-group">
                                            <label for="username">用户名:</label>
                                            <input type="text" id="username" class="form-control" disabled
                                                   value="{{ request.session.username }}"><!-- 用户名显示并且禁用 -->
                                        </div>
                                        <div class="form-group">
                                            <label for="old_password">原密码:</label>
                                            <input type="password" id="old_password" class="form-control">
                                        </div>
                                        <div class="form-group">
                                            <label for="new_password">新密码:</label>
                                            <input type="password" id="new_password" class="form-control">
                                        </div>
                                        <div class="form-group">
                                            <label for="re_password">确认密码:</label>
                                            <input type="password" id="re_password" class="form-control">
                                        </div>
                                        {# <input type="button" class="btn btn-success" value="提交">#}
                                        <div  class="pull-right">
                                            <button class="btn btn-success">提交</button>
                                        </div>
                                        <!-- button放在form表单中有自动提交的事件,下面script中需要阻止后续事件的执行 -->
                                        <br>
                                        <br>
                                        <br>
                                    </form>
                                    {# 修改密码结束 #}
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

        </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
</nav>
{# 导航条结束 #}

<!-- 剩下的布局分成3份 -->
<div class="container-fluid">
    <div class="row"><!-- 底下的分成3份,2,8,2分 -->
        <div class="col-md-2">
            <!-- 面板先占位置 -->
            <div class="panel panel-primary">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">Panel content</div>
                <div class="panel-body">Panel content</div>
                <div class="panel-body">Panel content</div>
                <div class="panel-body">Panel content</div>
                <div class="panel-body">Panel content</div>
                <div class="panel-body">Panel content</div>
            </div>
            <div class="panel panel-danger">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">Panel content</div>
                <div class="panel-body">Panel content</div>
            </div>
        </div>
        <div class="col-md-8">
            <!-- 中间是文章内容,使用媒体对象 -->
            <ul class="media-list">
                {% for article in article_list %}<!-- 循环所有文章对象的列表 -->
                    <li class="media">
                        <h4 class="media-heading"><a href="/{{ username }}/article/{{ article.pk }}">{{ article.title }}</a></h4><!-- 文章标题 -->
                        <div class="media-left">
                            <a href="#">
                                <!-- 显示文章列表中的avatar,使用media文件夹 -->
                                <!-- 文章对象.站点表(反向).用户表(反向) -->
                                <img class="media-object" src="/media/{{ article.blog.userinfo.avatar }}" alt="..." style="width: 70px;"><!-- 头像 -->
                            </a>
                        </div>
                        <div class="media-body">{{ article.desc }}</div><!-- 文章摘要 -->
                        <br>
                        <div>
                            <!-- xiezhr 2023-05-10 08:04  1   0 121 -->
                            <!-- 文章对象.站点表(反向).用户表(反向) -->
                            <span><a href="">{{ article.blog.userinfo.username }}</a></span>&nbsp;&nbsp;<!-- 用户名 -->
                            <span>{{ article.create_time|date:'Y-m-d' }}&nbsp;&nbsp;</span><!-- 注册时间 -->
                            <span><span class="glyphicon glyphicon-thumbs-up"></span>({{ article.up_num }})&nbsp;&nbsp;</span><!-- 点赞数 -->
                            <span><span class="glyphicon glyphicon-thumbs-down"></span>({{ article.down_num }})&nbsp;&nbsp;</span><!-- 点踩数 -->
                            <span><span class="glyphicon glyphicon-comment"></span>({{ article.comment_num }})&nbsp;&nbsp;</span><!-- 评论数 -->
                        </div>
                        <hr>
                    </li>
                {% endfor %}
            </ul>
        </div>
        <div class="col-md-2">
            <div class="panel panel-primary">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-primary">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-primary">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
        </div>
    </div>
</div>

<!-- 引入layer文件 -->
{#<script src="/static/layer/layer.js"></script>#}
<script src="/static/layer/layer.js"></script>
<script>
    // 修改密码提交事件
    $(".btn").click(function (e) {
        e.preventDefault();  // 阻止后续事件执行
        // 1. 获取参数
        var old_password = $("#old_password").val();
        var new_password = $("#new_password").val();
        var re_password = $("#re_password").val();

        // 2. 验证参数
        //if (!old_password) {
        //    layer.msg('原始密码不能为空');
        //    return;
        //}
        //if (!new_password) {
        //    layer.msg('新密码不能为空');
        //    return;
        //}
        //if (!re_password) {
        //    layer.msg('确认密码不能为空');
        //    return;
        //}

        // 3. 发起ajax请求,把密码输入的数据提交到后端
        $.ajax({
            url: '/set_password/',  // url不能省略,朝修改密码的路由提交post请求
            type: 'post',
            data: {
                old_password: old_password,
                new_password: new_password,
                re_password: re_password,
                csrfmiddlewaretoken: '{{ csrf_token }}'
            },
            success: function (res) {
                if (res.code == 200) {
                    // icon: 1
                    layer.msg(res.msg, {}, function () {
                        {#console.log(msg);#}
                        location.reload();  // 输入密码成功后刷新页面,或者也可以跳转到登录页面
                        // location.href = res.url;
                    })
                } else {
                    {#console.log(msg);#}
                    layer.msg(res.msg);
                }
            }
        })
    })
</script>
</body>
</html>

首页后端

后端代码

Django的分页器:https://www.cnblogs.com/zjyao/p/17378488.html

def home(request):
    """首页搭建"""
    # 展示所有的文章列表,查出文章表对象
    article_list = models.Article.objects.all()
    # print(article_list)  # QuerySet对象:[对象1,对象2]
    """文章过多的情况下,可以考虑添加分页器"""
    return render(request, 'home.html', locals())

前端重点

前端数据展示逻辑

5.首页数据展示
    文章标题
    图片:展示用户头像,文章查用户
    # 文章--> 站点(正向)--> 用户(反向)--> 点avatar
    文章摘要
    作者:文章查作者
    # 文章--> 站点(正向)--> 用户(反向)--> 点username
    文章创建时间,过滤器格式化
    文章点赞数
    文章点踩数
    文章评论数

文章旁的图片展示

6.图片上传到media文件夹中,配置上传路径(settings中配置路径),增加访问media接口(路由配置)
    6.1 settings中做配置,配置上传路径
    6.2 增加路由,增加访问接口 
    6.3 改变一下首页前端图片标签中的src地址,把/media/加上

图片展示不正常?

没有开设avater接口。项目中静态文件想要展示,需要开设接口的。图片文件,我们一般不开设avater接口,新开设一个media文件夹,把用户上传的图片单独防止在这个文件夹中。

1.settings中做配置,配置上传路径

# 只要配置了这句话,以后再上传图片的话,就会上传到这个文件夹下面去
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

2.增加路由,增加访问接口 # 暴漏该目录

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

# 如果你想访问media文件夹下的内容,必须开设一个接口对外访问
url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),  # 固定写法

修改密码

点击修改密码中弹出模态框

修改密码前端步骤

1.在修改密码的a标签中增加两个属性
data-toggle="modal" data-target=".bs-example-modal-lg"
2.模态框中第一个div标签的
class="modal fade"中增加一个类:bs-example-modal-lg
3.增加form表单数据框
	用户名显示并且禁用
	button在form表单自带提交事件,ajax中需要阻止后续事件的执行
4.ajax提交数据到后端re_password路由中
	4.1 绑定点击事件
    4.2 阻止后续事件执行,e.preventDefault();
    4.3 获取前端参数,3个密码参数
    4.4 验证参数
    4.5 发起ajax请求,朝后端提交数据,url必填,
    4.6 修改成功后,刷新页面location.reload()
    

修改密码后端

后端逻辑

# 只需要功能,不需要页面了,不用render
1.定义返回给前端的数据格式
2.接收参数
3.验证参数
4.正常逻辑
    4.1 修改密码必须登录之后,认证登录装饰器
    4.2 原始密码加密
    4.3 根据用户名(登录后在session中保存的)和密码查询用户是否存在
    4.4 没有查到返回信息
    4.5 新密码加密
    4.6 修改数据表中的新密码,根据pk(登录后在session中保存的id)筛选update(password=加密后的新密码)
    4.7 返回信息

认证登录的装饰器

def login_auth(func):
    """认证登录的装饰器"""

    def inner(request, *args, **kwargs):
        if request.session.get('username'):  # 用户存在,执行正常函数,用户不存在,调登录路由
            return func(request, *args, **kwargs)
        else:
            # return redirect('/login/')  # ajax请求,不能跳转页面,只会接收整个页面html代码数据,ajax只要结果
            return JsonResponse({'code': 201, 'msg': '请先登录', 'url': '/login/'})  # 返回json格式数据

    return inner

后端代码

@login_auth
def set_password(request):
    """修改密码"""
    if request.method == 'POST':
        # 1.定义返回前端的数据格式
        back_dic = {'code': 200, 'msg': '修改密码成功'}

        # 2.接收参数
        old_password = request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        re_password = request.POST.get('re_password')

        # 3.验证参数
        if not old_password:
            back_dic['code'] = 1009
            back_dic['msg'] = '原始密码不能为空'
            return JsonResponse(back_dic)
        if not new_password:
            back_dic['code'] = 1010
            back_dic['msg'] = '新密码不能为空'
            return JsonResponse(back_dic)
        if not re_password:
            back_dic['code'] = 1011
            back_dic['msg'] = '确认密码不能为空'
            return JsonResponse(back_dic)

        # 两次密码不一致
        if new_password != re_password:
            back_dic['code'] = 1005
            back_dic['msg'] = '两次密码不一致'
            return JsonResponse(back_dic)

        # 4.正常逻辑
        # 4.1 验证原始密码是正确
        old_pwd = get_md5_pwd(old_password)
        # 4.2 使用用户名和原始密码查询用户对象
        is_right = models.UserInfo.objects.filter(username=request.session.get('username'), password=old_pwd).first()
        print(is_right)
        if not is_right:  # 用户不存在
            back_dic['code'] = 1012
            back_dic['msg'] = '原始密码不正确'
            return JsonResponse(back_dic)
        # 4.3 修改新密码
        new_pwd = get_md5_pwd(new_password)
        # 4.4 入库
        models.UserInfo.objects.filter(pk=request.session.get('id')).update(password=new_pwd)
        return JsonResponse(back_dic)

退出登录

后端逻辑

1.清空session,用flush(),数据库和cookie都删
2.跳转到登录页面redirect('登录页面')

后端代码

def logout(request):
    """退出登录"""
    # 清空session
    request.session.flush()
    # 前端使用的是ajax提交的,后端不能在跳转了,需要自己在前端写路由地址
    return redirect('/login/')

后台数据模拟

用后台管理系统(admin路由)模拟数据。

1.注册表,把自己创建的所有表都注册到后台
在admin.py文件:

from django.contrib import admin

# Register your models here.

from app01 import models
# 想要在后台管理系统中显示表,需要在admin.py中注册表
# 只要注册了,admin就会自动生产针对该注册表的增删改查至少四个功能
admin.site.register(models.UserInfo)
admin.site.register(models.Blog)
admin.site.register(models.Tag)
admin.site.register(models.Category)
admin.site.register(models.Article)
admin.site.register(models.Article2Tag)
admin.site.register(models.UpAndDown)
admin.site.register(models.Comment)

2.修改admin后台管理的表名

class Meta:  # 元信息
    verbose_name_plural = '用户表'  

    # verbose_name = '用户表'    # 会显示:用户表s
    # 英文表名后台自动加个s

3.字段显示中文,给字段增加verbose_name属性

verbose_name='手机号'

4.添加数据,右上角的add

5.添加的外键显示对象,怎么显示相应name呢?

def __str__(self):
    return self.site_name

  1. 数据可以为空,字段加个属性blank=True
null=True, 代表的是数据库中可以为空
blank=True,代表的是django的后台页面上可以为空   

以上操作都跟数据库没有关系,不需要执行数据库迁移命令。
注意事项:绑定时,一定注意用户要对应,不要绑错了

复制整篇文章的html代码

点击id='cnblogs_post_body',右击copy,选择Copy outerHTML

总结点

总结button

button在form表单自带提交事件,ajax绑定点击事件后,点击提交就会产生二次提交,怎么改正?

  • 方式一:取消form表单,只显示输入框
  • 方式二:button按钮框写在form表单外面,就没有自动提交事件了
  • 方式三:仍然form中写button,在js中绑定点击事件后,写阻止后续事件的执行,用
e.preventDefault();
或者
return false;

阻止后续事件

如果前端使用的是ajax提交,后端就不能跳转了

因为ajax前端只要后端的结果,如果后端使用redirect('一个页面'),会返回给前端res一整个heml页面,不会跳转的。
为什么退出登录可以跳转,因为退出登录的前端是a链接,是个get请求,就可以直接重定向了

posted @ 2023-05-14 21:10  星空看海  阅读(8)  评论(0编辑  收藏  举报