文章相关功能
2380 字
12 分钟
文章相关功能
【三】手动录入数据
- 从文章表入手
- 录入文章需要个人站点 --- 创建个人站点
- 录入文章需要文章标签 --- 创建文章标签
- 文章与标签进行绑定
- 用户与个人站点进行绑定
【四】主页文章渲染
【1】需求分析
【2】视图函数
def home(request, *args, **kwargs): article_all = Article.objects.all() return render(request, "home.html", locals())【3】路由映射
from django.contrib import adminfrom django.urls import pathfrom django.urls.conf import includefrom blog.views import home
urlpatterns = [ path('admin/', admin.site.urls), path("", home, name="home"), path("user/", include("user.urls")), path("blog/", include("blog.urls")), path("article/", include("article.urls")),]【4】前端页面
{# 加载静态文件 #}{% load static %}{# 加载 inclusion_tag #}{% load CommonInclusionTag %}
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> {# <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>#} {# <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">#} {# <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>#} <script src="{% static 'js/jquery.min.js' %}"></script> <script src="{% static 'plugins/bootstrap/js/bootstrap.min.js' %}"></script> <link rel="stylesheet" href="{% static 'plugins/bootstrap/css/bootstrap.min.css' %}"> <script src="{% static 'js/sweetalert.min.js' %}"></script> <script src="{% static 'plugins/layui/layui/layui.js' %}"></script> <link rel="stylesheet" href="{% static 'plugins/layui/layui/css/layui.css' %}"></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="{% url '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="https://www.cnblogs.com/dream-ze" target="_blank">博客园</a></li> <li><a href="https://blog.csdn.net/Chimengmeng" target="_blank">CSDN</a></li> <li><a href="https://juejin.cn/" target="_blank">掘金</a></li> <li role="separator" class="divider"></li> <li><a href="https://gitee.com/chi-meng/bbs-related-projects" target="_blank">Gitee</a></li> </ul> </li> </ul> {# 搜索框 跳转百度页面 #} <form class="navbar-form navbar-left" id="searchForm"> <div class="form-group"> <input type="text" class="form-control" placeholder="放松一刻" id="searchText"> </div> <button type="submit" class="btn btn-default">百度一下</button> </form> {# 右侧登录注册导航栏 #} <ul class="nav navbar-nav navbar-right"> {# 利用auth模块的登陆认证功能,利用 Django的 模版语法,判断当前用户是否登录 #} {# 如果当前用户处于登陆状态则将右侧登录注册隐藏,渲染当前个人信息 #} {% if request.user.is_authenticated %} {# 渲染当前用户的头像 #} <li> <img src="{{ request.user.avatar }}" alt="缓冲中 ~~~ " class="img-circle" style="height: 48px;width: 48px"> </li> {# 页面显示当前登录的用户名 #} <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"> {{ request.user.username }}[ {% if request.user.is_superuser %} 管理员 {% else %} 用户 {% endif %} ] <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="#">个人信息</a></li> <li><a href="{% url 'adv' %}">添加广告</a></li> <li role="separator" class="divider"></li> <li><a href="{% url 'logout' %}">注销登陆</a></li> </ul> </li> {# 如果当前用户处于未登录的状态,则渲染注册和登陆框 #} {% else %} <li><a href="{% url 'register' %}">注册</a></li> <li><a href="{% url 'login' %}">登陆</a></li> {% endif %} </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --></nav>{# 导航条结束 #}
{# 修改密码模态框开始 #}<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"> <div class="modal-header"> {# 右上角关闭模态框的 x #} <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> {# 大标题 : 修改密码页面 #} <h4 class="modal-title text-center" id="myLargeModalLabel">修改密码</h4> </div> <div class="modal-body"> <div class="row"> <div class="col-md-6 col-md-offset-3"> {# 定义form表单,但是仍然不走 form 表单提交数据,而是使用ajax #} <form id="reset_password_form"> <div class="form-group"> <label for="inputUsername">用户名 : </label> <input type="text" class="form-control" name="username" id="inputUsername" value="{{ request.user.username }}" disabled> </div> <div class="form-group"> <label for="inputOldPassword">旧密码 : </label> <input type="text" class="form-control" name="old_password" id="inputOldPassword" placeholder="old_password"> </div> <div class="form-group"> <label for="inputNewPassword">新密码 : </label> <input type="text" class="form-control" name="new_password" id="inputNewPassword" placeholder="new_password"> </div> <div class="form-group"> <label for="inputConfirmPassword">确认密码 : </label> <input type="text" class="form-control" name="confirm_password" id="inputConfirmPassword" placeholder="confirm_password"> </div> {# 定义点击修改按钮 #} <div class="form-group"> <input type="button" class="btn btn-warning btn-block" value="确认修改" id="btn_reset_password"> </div> </form> </div> </div> </div> </div> </div></div>{# 修改密码模态框结束 #}
{# 主题框架搭建开始 #}{% block content_outer %} <div class="container-fluid"> <div class="row"> {# 左侧广告栏 #} <div class="col-md-2"> {% home_adv %} </div>
{# 中间主题内容 #} <div class="col-md-8"> {% block content_main %} {# 渲染所有用的文章 #} {% for article_obj in article_all %} {# 每一篇文章对象都是一个小的组件 #} <div class="media"> {# 渲染文章标题 #} <h4 class="media-heading"><a href="">{{ article_obj.title }}</a></h4> {# 渲染左侧侧边头像 #} <div class="media-left"> <a href="#"> <img class="media-object" data-src="holder.js/64x64" alt="64x64" src="{{ article_obj.blog.userinfo.avatar }}" data-holder-rendered="true" style="width: 64px; height: 64px;"> </a> </div> {# 渲染文章的简介信息 #} <div class="media-body"> {# 有文章简介时渲染文章简介 #} {% if article_obj.desc %} {{ article_obj.desc }} {# 没有文章简介时,渲染当前文章内容的前 30 个字符 #} {% else %} {{ article_obj.content|truncatechars:30 }} ... {% endif %} </div> {# 加一个换行美观页面 #} <br> {# 渲染底部的 作者 发布日期 点赞数 点踩数 评论数 #} <div> {# 当前文章作者 跨表查询 从文章表出发 --> 个人站点表 ---> 用户表 #} <a href="" style="padding-right: 10px">{{ article_obj.blog.userinfo.username }}</a> {# 文章发布时间,做前端模板的格式化输出语法 #} <span style="padding-right: 10px">{{ article_obj.create_time|date:"Y-m-d H:i:s" }}</span> {# 当前文章的点赞数图标及数量 , 图标来自于 bootstrap #} <span style="padding-right: 10px"> <span class="glyphicon glyphicon-thumbs-up"></span> {{ article_obj.up_num }} </span> {# 当前文章的点踩数图标及数量 , 图标来自于 bootstrap #} <span style="padding-right: 10px"> <span class="glyphicon glyphicon-thumbs-down"></span> {{ article_obj.down_num }} </span> {# 当前文章的评论数图标及数量 , 图标来自于 bootstrap #} <span style="padding-right: 10px"> <span class="glyphicon glyphicon-comment"></span> {{ article_obj.comment_num }} </span> </div> </div> {# 美化页面,每一篇文章信息都加一个横线划分 #} <hr> {% endfor %} {% endblock %} </div>
{# 右侧广告栏 #} <div class="col-md-2"> {% home_adv %} </div> </div> </div>{% endblock %}
{# 主题框架搭建结束 #}
{# js文件书写位置 #}{# 百度搜索框点击搜索事件开始 #}<script> $(document).ready(function () { // 定义函数 function search() { // 使用jQuery获取输入框中的值 let keyword = $("#searchText").val(); // 构造跳转到百度搜索的链接 let urlTag = "https://www.baidu.com/s?wd=" + encodeURIComponent(keyword); // 在新窗口中打开链接 window.open(urlTag, "_blank"); }
// 给搜索按钮绑定点击事件 $("#searchForm").submit(function (event) { // 阻止表单默认提交行为 event.preventDefault(); // 调用搜索函数 search(); });
// 修改密码按钮点击事件 $("#btn_reset_password").on("click", function () { // 使用 sweetalert 的弹框确认事件 swal({ title: "修改密码操作不可逆!", text: "一旦密码被修改,无法找回原密码,确认修改吗?", icon: "warning", buttons: true, dangerMode: true, }).then((willReset) => { // 判断用户是否点击了确认按钮 if (willReset) { let data = {} $.each($("#reset_password_form").serializeArray(), function (index, dataDict) { data[dataDict.name] = dataDict.value }) data["csrfmiddlewaretoken"] = "{{ csrf_token }}" $.ajax({ url: "{% url 'reset_password' %}", type: "post", data: data, success: (response) => { if (response.code === 200) { swal({ title: response.message, icon: "success", button: true, }).then(() => { window.location.href = response.next_url; }); } else { swal({ title: response.errors, icon: "error", button: true, }).then(() => { window.location.reload() }); } } }) } else { swal("好好想一想哦 ~ ~ ~ "); } }); }) });</script>{# 百度搜索框点击搜索事件结束 #}
</body></html>【五】个人站点文章
【1】需求分析
【2】视图函数
# 个人站点视图def site(request, username, *args, **kwargs): # 【一】校验当前用户是否存在,如果不存在则返回 404 error 页面 if not UserInfo.objects.filter(username=username).exists(): return render(request, "errors/404.html", locals()) # 【二】用户名存在则返回当前用户视图 # 筛选出当前用户下的所有文章数据 article_list = Article.objects.filter(blog__userinfo__username=username).all()
return render(request, "site.html", locals())【3】路由映射
# 个人站点路由path("site/<slug:username>/", site, name="site"),【4】前端页面
(1)注册侧边栏
- blog/templatetags/CommonInclusionTag.py
@register.inclusion_tag("inclusion_tags/article_left.html")def article_left(user_obj): # user_obj : 当前登录的用户对象
# 【一】获取当前用户下所有的标签分类名称 # 跨表查询:从关联的 用户 表中查询出当前用户的个人站点 # article_category_class = CategoryClass.objects.filter(blog=user_obj.blog) # 【二】获取当前用户下的所有分类及分类下的文章数 article_category_class = CategoryClass.objects.filter(blog=user_obj.blog).annotate( article_num=Count('article__pk')).values("name", "article_num")
# 【三】获取当前用户下所有的标签名称 # article_category_tags = CategoryTag.objects.filter(blog=user_obj.blog) # 【四】获取当前用户下的所有标签及标签下的文章数 article_category_tags = CategoryTag.objects.filter(blog=user_obj.blog).annotate( article_num=Count('article__pk')).values("name", "article_num")
# 【四】获取当前用户下的所有文章的日期(按照年月分组) # 日期归档 官网提供了一个关于日期字段的切割数据的方法 # https://docs.djangoproject.com/zh-hans/3.2/ref/models/database-functions/#trunc # 不要忘了修改配置 # 切换时区为亚洲上海 : TIME_ZONE = 'Asia/Shanghai' # USE_TZ = False article_list = Article.objects.filter(blog=user_obj.blog).annotate(month=TruncMonth("create_time")).annotate( article_num=Count("pk")).values("month", "article_num") print(article_list)
# 【五】获取当前用户下的所有文章点赞数 article_up = Article.objects.filter(blog=user_obj.blog).order_by("-up_num").values("title", "up_num")
return locals()- blog/templates/inclusion_tags/article_left.html
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head><body>{# 随笔分类 块 #}<div class="list-group"> {# 头部 标题 #} <a href="#" class="list-group-item active"> 随笔分类 </a> {# 遍历每一个文章对象 #} {% for article_category_class_obj in article_category_class %} <a href="#" class="list-group-item"> {{ article_category_class_obj.name }} ({{ article_category_class_obj.article_num }}) </a> {% endfor %}</div>{# 随笔标签块 #}<div class="list-group"> {# 头部 标题 #} <a href="#" class="list-group-item active"> 随笔标签 </a> {# 遍历每一个文章标签和文章对象 #} {% for article_category_tag_obj in article_category_tags %} <a href="#" class="list-group-item"> {{ article_category_tag_obj.name }} ({{ article_category_tag_obj.article_num }}) </a> {% endfor %}
</div>{# 随笔归档块 #}<div class="list-group"> {# 头部 标题 #} <a href="#" class="list-group-item active"> 随笔档案 </a> {# 遍历所有筛选过后的文章对象 #} {% for article_obj in article_list %} {# 获取每一个文章对象中的 归档后的月份 和 文章数 #} <a href="#" class="list-group-item">{{ article_obj.month|date:"Y-m" }} ({{ article_obj.article_num }})</a> {% endfor %}
</div><div class="list-group"> <a href="#" class="list-group-item active"> 点赞排行 </a> {% for article_obj in article_up %} <a href="#" class="list-group-item">{{ article_obj.title }} ({{ article_obj.up_num }})</a> {% endfor %}</div></body></html>(2)个人站点页
{% extends 'home.html' %}
{% block title %} {{ request.user.blog.site_title }}{% endblock %}{% block content_outer %} <div class="container-fluid"> <div class="row"> {# 左面三分为侧边 展示栏 #} <div class="col-md-2"> {# 加载 inclusion_tag 标签 #} {% load CommonInclusionTag %} {# 调用自定义的标签,参数为当前登录用户的对象 #} {% article_left request.user %} </div> {# 右边九份为文章展示栏 #} <div class="col-md-10"> {# 右上角的随笔总数 #} <div class="pull-right"> 随笔 - {{ article_list.count }} </div> {# 换行为了好看 #} <br> {# 遍历每一篇文章对象进行渲染 #} {% for article_obj in article_list %} <div class="media"> {# 主体 部分 渲染 文章的标题和简介 #} <div class="media-body"> <h4 class="media-heading"><a href="">{{ article_obj.title }}</a></h4> <hr> <span>{{ article_obj.desc }}</span> </div> {# 底部渲染 文章的发布日期,作者,点赞数,点踩数,评论数,编辑按钮等 #} <div class="media-bottom pull-right"> posted @ {{ article_obj.create_time|date:"Y-m-d H:i:s" }} <a href="">{{ article_obj.blog.userinfo.username }}</a> 点赞 {{ article_obj.up_num }} 点踩 {{ article_obj.down_num }} 评论 {{ article_obj.comment_num }} <a href="">编辑</a> </div> </div> {# 换行是为了好看 #} <br> {% endfor %} </div> </div> </div>{% endblock %}支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!
相关文章智能推荐
1
C 语言发展史
编程语言了解 C 语言从 BCPL、B 语言到现代标准 C 的发展历程、核心特点与应用领域。
2
C 语言开发环境的安装与配置
编程语言在 Windows、Linux 与 macOS 上安装 C 工具链,配置编辑器,并编译运行第一个 C 程序。
3
C 语言初识:程序运行机制与基本结构
编程语言认识 C 程序从源代码到运行的完整流程,以及基础语法和程序的基本结构。
4
C 语言基础:注释、关键字、变量与数据类型
编程语言学习 C 语言的注释、关键字、标识符、常量、变量和基本数据类型等基础知识。
5
C 语言数据类型
编程语言理解 C 语言的数据类型体系,包括基本类型、整数类型、浮点类型和逻辑类型。
随机文章随机推荐














