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&nbsp;&nbsp;</span>
                <span>@&nbsp;&nbsp;</span>
                <span>{{ article_obj.create_time|date:'Y-m-d' }}&nbsp;&nbsp;</span>
                <span>{{ article_obj.blog.userinfo.username }}&nbsp;&nbsp;</span>
                <span><span
                        class="glyphicon glyphicon-thumbs-up"></span>&nbsp;{{ article_obj.up_num }}&nbsp;&nbsp;</span>
                <span><span
                        class="glyphicon glyphicon-comment"></span>&nbsp;{{ article_obj.comment_num }}&nbsp;&nbsp;</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函数中获取数据。

posted @   不会钓鱼的猫  阅读(28)  评论(0编辑  收藏  举报
编辑推荐:
· 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训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示