BBS项目-文章详情页
1 详情页分析
参考博客园文章详情页,可以看出,文章详情页和个人站点页面基本一致,首页和左边侧边栏是不变的。因此可以用模版继承。
继续分析博客园文章详情页的url
https://www.cnblogs.com/cqzlei/articles/16999040.html
我们的url可以设计成,/username/article/article_id, 路由设计如下
re_path(r'^(?P<username>\w+)/article/(?P<article_id>\d+)', views.article_detail)
views.py 写一个简单视图,验证路由是否会被其他url顶替,网址输入http://127.0.0.1:8000/jason/article/1, 页面返回ok
def article_detail(request, username, article_id):
return HttpResponse('ok')
2 后端接口逻辑
def article_detail(request, username, article_id):
user_obj = models.UserInfo.objects.filter(username=username).first()
blog = user_obj.blog # 获取blog对象返回给前端,导航条需要渲染blog.site_title,显示站点标题
# 获取站点名是username,并且文章主键是article_id的文章对象,返回给前端展示
article_obj = models.Article.objects.filter(blog=blog, pk=article_id).first()
if not article_obj:
return render(request, '404error.html')
return render(request, 'article_detail.html', locals())
3 模板继承
文章详情页和个人站点页面基本一致,利用模板的继承。先创建一个模板, base.html。 把写好的site.html的内容拷贝到模板,左侧边栏是固定的,文章详情页和个人站点页不同之处在于右边主体展示部分,这部分用block块占位。
个人站点页继承模板页面,之前的内容清除掉,只在blocke块填充内容,site.html
{% extends 'base.html' %}
{% block content %}
<ul class="media-list">
{% for article_obj in page_queryset %}
<h4 class="media-heading"><a href="#">{{ article_obj.title }}</a></h4>
<li class="media">
<div class="media-left">
<a href="#">
<img class="media-object" src="/media/{{ article_obj.blog.userinfo.avatar }}" alt="..."
width="60">
</a>
</div>
<div class="media-body">
{{ article_obj.desc }}
</div>
</li>
<div class="pull-right">
<span>posted </span>
<span>@ </span>
<span>{{ article_obj.create_time|date:'Y-m-d' }} </span>
<span>{{ article_obj.blog.userinfo.username }} </span>
<span><span
class="glyphicon glyphicon-thumbs-up"></span> {{ article_obj.up_num }} </span>
<span><span
class="glyphicon glyphicon-comment"></span> {{ article_obj.comment_num }} </span>
<span><a href="#">编辑</a></span>
</div>
<hr>
{% endfor %}
<h5 class="text-center">{{ page_obj.page_html|safe }}</h5>
</ul>
{% endblock %}
文章详情页继承模板页面,只在blocke块填充内容,article_detail.html
{% extends 'base.html' %}
{% block content %}
<h1>{{ article_obj.title }}</h1>
<div class="content">
{{ article_obj.content }}
</div>
{% endblock %}
接下来补全首页和个人站点页跳转到文章详情页的a标签的url
<!--site.html 文章标题-->
<h4 class="media-heading"><a href="/{{ username }}/article/{{ article_obj.pk }}/">{{ article_obj.title }}</a></h4>
<!--home.html 文章标题-->
<h4 class="media-heading"><a href="/{{ article_obj.blog.userinfo.username }}/article/{{ article_obj.pk }}">{{ article_obj.title }}</a></h4>
4 侧边栏自定义inclusion_tag
文章详情页完成后,页面效果如下:
文章详情页的侧边栏没有内容。因为侧边栏展示需要传输数据才能渲染。
我们后端的个人站点接口,返回了数据。而文章详情接口并没有返回。
文章详情页侧边栏如果想要渲染数据,简单的方法是直接把上图查询数据的代码拷贝到后端接口,但是这样会很繁琐,代码冗余。
侧边栏的渲染需要传输数据才能渲染,并且该侧边栏在很多页面都需要使用,可以将侧边栏制作成inclusion_tag。
自定步骤如下:
1.在应用下创建一个名字必须叫templatetags文件夹
2.在该文件夹内创建一个任意名称的py文件
3.在该py文件内先固定写两行代码
from django import template
register = template.Library()
# 自定义过滤器
# 自定义标签
# 自定义inclusion_tag
app01/templatetags/mytag.py
把 site.html中查询分类、标签、日期数据的代码拷贝过来,补齐所需的模块,left_menu函数需要传入username形参。
from django import template
from app01 import models
from django.db.models import Count
from django.db.models.functions import TruncMonth
register = template.Library()
# 自定义inclusion_tag
@register.inclusion_tag('left_menu.html')
def left_menu(username):
user_obj = models.UserInfo.objects.filter(username=username).first()
blog = user_obj.blog
categorize_list = models.Categorize.objects.filter(blog=blog).annotate(
article_num=Count('article__pk')).values_list('name', 'article_num', 'pk')
tag_list = models.Tag.objects.filter(blog=blog).annotate(article_num=Count('article__pk')).values_list('name',
'article_num',
'pk')
date_list = models.Article.objects.filter(blog=blog).annotate(month=TruncMonth('create_time')).values(
'month').annotate(article_num=Count('pk')).values_list('month', 'article_num')
return locals()
创建 left_menu.html 页面,即inclusion_tag页面,把 base.html中侧边栏的部分拷贝过去。
base.html 页面中导入自定义的inclusion_tag, 调用 left_menu函数, 并传入username参数,因为个人站点页和文章详情页共用的base模板,正好两个后端接口都返回了username,在base.html 能够获取到username。
base.html
<div class="container-fluid">
<div class="row">
<div class="col-md-3">
{% load mytag %} <!--导入inclusion_tag-->
{% left_menu username %} <!--调用自定义函数,传入参数username-->
</div>
<div class="col-md-9">
{% block content %}
{% endblock %}
</div>
</div>
</div>
用了inclusion_tag后,后端 site 接口查询分类、标签、日期的几行代码可以省略掉,因为都在 left_menu函数中获取数据。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人