登录        注册
本站基于Django开发,源码 Github 欢迎 Fork、Star。由于站点升级导致评论区留言信息丢失,欢迎前来发表新的评论

Django个人博客开发十二 | 博客详情页面

Django stormsha 6067浏览 216喜欢 2评论
本渣渣不专注技术,只专注使用技术,不是一个资深的coder,是一个不折不扣的copier

1、博客详情页面

博客的详情页同样继承自 base.html 模板,侧边栏就不需要了,这里老规矩,不一块一块的讲解,这个自己要

blog -> storm -> view.py

class DetailView(generic.DetailView):
    """
        Django有基于类的视图DetailView,用于显示一个对象的详情页,我们继承它
    """
    # 获取数据库中的文章列表
    model = Article

    # template_name属性用于指定使用哪个模板进行渲染
    template_name = 'article.html'

    # context_object_name属性用于给上下文变量取名(在模板中使用该名字)
    context_object_name = 'article'

    def get_object(self):
        obj = super(DetailView, self).get_object()
        # 设置浏览量增加时间判断,同一篇文章两次浏览超过半小时才重新统计阅览量,作者浏览忽略
        u = self.request.user
        ses = self.request.session
        the_key = 'is_read_{}'.format(obj.id)
        is_read_time = ses.get(the_key)
        if u != obj.author:
            if not is_read_time:
                obj.update_views()
                ses[the_key] = time.time()
            else:
                now_time = time.time()
                t = now_time - is_read_time
                if t > 60 * 30:
                    obj.update_views()
                    ses[the_key] = time.time()
        # 文章可以使用markdown书写,带格式的文章,像csdn写markdown文章一样
        md = markdown.Markdown(extensions=[
            'markdown.extensions.extra',
            'markdown.extensions.codehilite',
            TocExtension(slugify=slugify),
        ])
        obj.body = md.convert(obj.body)
        obj.toc = md.toc
        return obj

    def get_context_data(self, **kwargs):
        context = super(DetailView, self).get_context_data(**kwargs)
        context['category'] = self.object.id
        return context

blog -> storm -> urls.py

# ---------------------------
__author__='stormsha'
__date__='2019/3/10 21:03'
# ---------------------------
from django.conf.urls import url
from .views import IndexView, DetailView

urlpatterns = [
    # 首页
    url(r'^$', IndexView.as_view(template_name='index.html'), name='index'),  # 主页,自然排序
    # 给我留言
    url(r'^category/message/$', MessageView, name='message'),
    # 关于自己
    url(r'^category/about/$', AboutView, name='about'),
    # 赞助作者
    url(r'^category/donate/$', DonateView, name='donate'),
    # 技术交流
    url(r'^category/exchange/$', ExchangeView, name='exchange'),
    # 项目合作
    url(r'^category/project/$', ProjectView, name='project'),
    # 提问交流
    url(r'^category/question/$', QuestionView, name='question'),
    # 分类页面
    url(r'^category/(?P<bigslug>.*?)/(?P<slug>.*?)', IndexView.as_view(template_name='content.html'), name='category'),
    # 归档页面
    url(r'^date/(?P<year>\d+)/(?P<month>\d+)/$', IndexView.as_view(template_name='archive.html'), name='date'),
    # 标签页面
    url(r'^tag/(?P<tag>.*?)/$', IndexView.as_view(template_name='content.html'), name='tag'),
    # 文章详情页面
    url(r'^article/(?P<slug>.*?)/$', DetailView.as_view(), name='article'),
]

新添加的路由

url(r'^article/(?P<slug>.*?)/$', DetailView.as_view(), name='article'),

首页模板文章列表部分代码

    <!--文章导航条-->
    <header>
        <!--lower 统一英文字符为小写-->
        <a class="label label-important" href="/category/{{ article.category.bigcategory.name }}/{{ article.category.name|lower }}">{{ article.category.name }}<i class="label-arrow"></i>
        </a>
        <!--文章标题-->
        <h2>
            <a target="_blank" href="/article/{{ article.slug }}" title="{{ article.title }}">{{ article.title }} </a>
        </h2>
    </header>

    <!--文章缩略图-->
    <div class="focus">
        <a target="_blank" href="/article/{{ article.slug }}"><img class="thumb" width="200"    height="123" src="{{ article.img_link }}" alt="{{ article.title }}"/>
        </a>
    </div>

前端请求的路径,带一个文章slug参数、slug是文章的唯一标识符,也称作文章别名,别问有啥用,就是提升逼格

/article/{{ article.slug }}

详情页模板

这里只展示部分代码做说明,源码参照Github

blog -> templates -> article.html

    <article class="article-content">
        # 文章内容,safe过滤器,把文章中带的标签转换成浏览器可解析的编码
        {{ article.body|safe }}
        <p>转载请注明:
            <a href="{% url 'blog:article' object.slug %}">StormSha</a> &raquo;
            <a href="{% url 'blog:article' object.slug %}">{{ object.title }}</a>
        </p>
    </article>

object: 是通用基类方法get_object返回的文章详情对象

推荐阅读:通用基类

2、实现博客的上一篇与下一篇功能

为了实现这个功能,我们需要在templatetags中获取该篇博客的上一篇博客以及下一篇博客。为了实现这个功能,我们需要考虑到以下2种情况:

博客的id号有可能是不连续的,当我们删除一篇博客时,连带着该id号一块删除了,如果通过blog_id - 1和blog_id+1来获取博客的上一篇与下一篇,则有可能会出错。如果是第一篇博客,它是没有上一篇的;同样,最后一篇博客也是没有下一篇的 因此,我们可以使用状态码has_prev和has_next来判断博客是否有上一篇和下一篇,并通过对id进行循环来判断id号码的连续性,实现代码如下:

blog -> templatetags -> blog_tags.py

# 获取前一篇文章,参数当前文章 ID
@register.simple_tag
def get_article_previous(article_id):
    has_previous = False
    id_previous = int(article_id)
    while not has_previous and id_previous >= 1:
        article_previous = Article.objects.filter(id=id_previous - 1).first()
        if not article_previous:
            id_previous -= 1
        else:
            has_previous = True
    if has_previous:
        article = Article.objects.filter(id=id_previous).first()
        return article
    else:
        return


# 获取下一篇文章,参数当前文章 ID
@register.simple_tag
def get_article_next(article_id):
    has_next = False
    id_next = int(article_id)
    article_id_max = Article.objects.all().order_by('-id').first()
    id_max = article_id_max.id
    while not has_next and id_next <= id_max:
        article_next = Article.objects.filter(id=id_next + 1).first()
        if not article_next:
            id_next += 1
        else:
            has_next = True
    if has_next:
        article = Article.objects.filter(id=id_next).first()
        return article
    else:
        return

blog -> templates -> article.html

    <nav class="article-nav">
        <span class="article-nav-prev">
            <i class="fa fa-angle-double-left"></i>
            {% get_article_previous object.id as article_previous %}
            <a href="{% url 'blog:article'  article_previous.slug %}" rel="prev">{{ article_previous.title }}</a>
        </span>
        <span class="article-nav-next">
            {% get_article_next object.id as article_next %}
            <a href="{% url 'blog:article'  article_next.slug %}" rel="prev">{{ article_next.title }}</a>
            <i class="fa fa-angle-double-right"></i>
        </span>
    </nav>

如此,即可实现博客的上一篇与下一篇功能。

    {% include 'comment_list.html' %}

源码详情页中的评论功能,再用户注册、登录、修改个人中心后讲解,重要的留在最后

【友情提示】——如果发现有表达错误,或者知识点错误,或者搞不懂的地方,请及时留言,可以在评论区互相帮助,让后来者少走弯路是我的初衷。我也是一步步摸着石头走过来的,深知网络上只言片语的图文教程,给初学者带来的深深困扰。

【建议】——在对项目结构不太熟悉时,参照完整源码少走弯路

转载请注明: StormSha » Django个人博客开发十二 | 博客详情页面

发表我的评论

表情
(2)个小伙伴在吐槽|2条评论
  1. 注册用户头像

    url(r'^article/(?P<slug>.*?)/$', DetailView.as_view(), name='article')这一段里的.*?问号是不是多余了?我也是在学习中,说错莫怪

    空灵心梦 2019年11月22日 17:55 回复
    • 不多于,url(r'^article/(?P<slug>.*?)/$', DetailView.as_view(), name='article') .*? 可以改为 [-\w+].*. 都可以,如果直接把 .*? 去掉是不可以,这里的原理是正则匹配,<slug> 是把匹配到的内容赋值给 slug

      stormsha 「博主」 @空灵心梦 2019年11月22日 21:03 回复