登录        注册
 本站基于Django1.11开发,源码已共享在 Github 欢迎 Fork、Star.近期站点微调频繁,如遇访问异常希望见谅,若能在评论区留言,或者发送邮件指出BUG,更是万分感谢

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

Django stormsha 1598浏览 0评论
本渣渣不专注技术,只专注使用技术,不是一个资深的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个人博客开发十二 | 博客详情页面

喜欢 (207) or 分享 ( 0)

联系我请直接在公众号留言~

扫码或搜索:进击的Coder

进击的Coder

微信公众号 扫一扫关注

想结交更多的朋友吗?

来进击的Coder瞧瞧吧

进击的Coder

QQ群号 213037458 立即加入

进击的Coder灌水太多?

这里是纯粹的技术领地

激进的Coder

QQ群号 781587463 立即加入

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请狠狠点击下面的

发表我的评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(5)个小伙伴在吐槽
  1. @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

    上一篇/下一篇的逻辑有点问题,以下一篇的为例(上述代码)
    比如当前article_id 为 2 ,且存在 article_id 为 3 的文章,这时候返回的还是 article_id = 2的文章,我修改了下:
    @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 article_next:
    has_next = True
    id=id_next +=1
    if has_next:
    article = Article.objects.filter(id=id_next).first()
    return article
    else:
    return

    博主分享的精神真的很棒

    Hanger2019-05-08 17:47:32回复
    • 恩恩,是有问题,最新更新的代码已经处理了这个问题,谢谢分享,欢迎在评论区留下学习中遇到的问题,让他人少走弯路

      stormsha2019-05-09 20:44:55回复
    • @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).first()
      if article_next:
      has_next = True
      id_next += 1
      if has_next:
      article = Article.objects.filter(id=id_next).first()
      return article
      else:
      return

      |橙黄橘绿|2019-07-20 09:37:26回复
    • '''python
      @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).first()
      if article_next:
      has_next = True
      id_next += 1
      if has_next:
      article = Article.objects.filter(id=id_next).first()
      return article
      else:
      return
      '''

      |橙黄橘绿|2019-07-20 09:42:56回复
  2. ![图片Al````t](http:/[链接描述](http://![图片Alt](http:/[链接描述](http://

    Column 1 Column 2 Column 3
    Text Text Text

    )/)``

    2222222019-07-24 18:22:27回复
    • 图片Alt

      2222222019-07-24 18:25:44回复
      • :smile:

        unsame2019-08-04 21:18:48回复
        • :mrgreen:

          unsame2019-08-04 21:19:27回复