zoukankan      html  css  js  c++  java
  • 文章详情页

    一、文章详情页访问设计

      访问文章详情页,访问文章路径类似:https://www.cnblogs.com/wupeiqi/articles/3148888.html

      参照访问路径编写文章详情页路由如下:

    urlpatterns = [
        ...
        # 文章详情页
        re_path('^(?P<username>w+)/articles/(?P<article_id>d+)$', views.article_detail),
    ]
    

    二、文章详情页的数据构建

      文章详情页的head部分和左侧区域应该和个人站点保持一致。因此需要用到继承extend。

    1、创建并编写base.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <!-- 引入 Bootstrap 核心 CSS 文件 -->
        <link rel="stylesheet" href="/static/blog/bootstrap-3.3.7/css/bootstrap.css">
        <!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
        <script src="/static/js/jquery-3.3.1.js"></script>
        <!-- 引入 Bootstrap 核心 JavaScript 文件 -->
        <script src="/static/blog/bootstrap-3.3.7/js/bootstrap.js"></script> <!--依赖jquery-->
        <style>
            * {
                margin: 0;
                padding: 0;
            }
    
            .header {
                 100%;
                height: 60px;
                background-color: #369;
            }
    
            .header .title {
                font-size: 18px; /* 字体大小 */
                font-weight: 100; /* 字体粗细 */
                line-height: 60px; /* 行高与页头一致,完成居中 */
                color: white;
                margin-left: 15px;
                margin-top: -10px;
            }
    
            .backend {
                float: right; /* 浮动到右边 */
                color: white;
                text-decoration: none; /* 去除下划线 */
                font-size: 16px;
                margin-right: 12px;
                margin-top: 10px;
            }
            .pub_info {
                margin-top: 10px;
                color: darkgray;
            }
        </style>
    </head>
    <body>
    
    <div class="header">
        <div class="content">
            <!--站点标题-->
            <p class="title">
                <span>{{ blog.title }}</span>
                <a href="" class="backend">管理</a>
            </p>
        </div>
    </div>
    
    <div class="container">
        <div class="row">
            <div class="col-md-3">
                <!--添加bootstrap面板-->
                <div class="panel panel-warning">
                    <div class="panel-heading">我的标签</div>
                    <div class="panel-body">
                        {% for tag in tag_list %}
                            <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p>
                        {% endfor %}
                    </div>
                </div>
                <div class="panel panel-danger">
                    <div class="panel-heading">随笔分类</div>
                    <div class="panel-body">
                        {% for cate in cate_list %}
                            <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p>
                        {% endfor %}
                    </div>
                </div>
                <div class="panel panel-success">
                    <div class="panel-heading">随笔归档</div>
                    <div class="panel-body">
                        {% for date in date_list %}
                            <p><a href="/{{ username }}/archive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p>
                        {% endfor %}
                    </div>
                </div>
            </div>
            <div class="col-md-9">
                {% block content %}
    
                {% endblock %}
            </div>
        </div>
    </div>
    
    </body>
    </html>
    

      注意:base.html保留了原先home_site.html大部分代码,将col-md-9的部分替换为如下:

    <div class="col-md-9">
        {% block content %}
    
        {% endblock %}
    </div>
    

      block 告诉模版引擎: 子模版可能会覆盖掉模版中的这些位置

    2、修改home_site.html继承base.html

    {% extends 'base.html' %}
    
    {% block content %}
        <div class="article_list">
                    <div class="article_list">
                        {% for article in article_list %}
                            <div class="article-item clearfix">
                                <h5><a href="">{{ article.title }}</a></h5>
                                <div class="article-desc">
                                    {# 文章摘要 #}
                                    {{ article.desc }}
                                </div>
                                <!--文章下方详细信息-->
                                <div class="small pub_info pull-right">
                                    {# 文章发布时间 #}
                                    <span>发布于  {{ article.create_time|date:"Y-m-d H:i" }}</span>   
                                    {# 评论数 #}
                                    <span class="glyphicon glyphicon-comment"></span> 评论({{ article.comment_count }})  
                                    {# 点赞数 #}
                                    <span class="glyphicon glyphicon-thumbs-up"></span> 点赞({{ article.up_count }})
                                </div>
                            </div>
                            <hr>
                        {% endfor %}
                    </div>
                </div>
    {% endblock %}
    

      extends 标签是这里的关键。它告诉模版引擎,这个模版“继承”了另一个模版。当模版系统处理这个模版时,首先将定位父模版——在此例中,就是“base.html”。

      模版引擎将注意到 base.html 中的 block 标签,并用子模版中的内容来替换这些block。

      

    3、详情页面head部分和左侧区域数据引入

    (1)方法一

      由于home_site.html和article_detail.html都需要引入如下数据:

    user = UserInfo.objects.filter(username=username).first()
    blog = user.blog
    
    cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title"))
        .values_list("title", "c")
    
    tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article"))
        .values_list("title", "c")
    
    date_list = models.Article.objects.filter(user=user).extra(select={"y_m_date": "date_format(create_time, '%%Y-%%m')"})
        .values("y_m_date").annotate(c=Count("nid")).values_list("y_m_date", "c")
    

      在views.py中定义一个新的函数get_classification_data:

    def get_classification_data(username):
        user = UserInfo.objects.filter(username=username).first()
        blog = user.blog
    
        cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")) 
            .values_list("title", "c")
    
        tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")) 
            .values_list("title", "c")
    
        date_list = models.Article.objects.filter(user=user).extra(
            select={"y_m_date": "date_format(create_time, '%%Y-%%m')"}) 
            .values("y_m_date").annotate(c=Count("nid")).values_list("y_m_date", "c")
        return {"blog": blog, "cate_list": cate_list, "tag_list": tag_list, "date_list": date_list}
    

      依此可以改写视图函数home_site和article_detail,以article_detail为例:

    def article_detail(request, username, article_id):
    
        context = get_classification_data(username)
    
        return render(request, "article_detail.html", context)
    

     方法二:运用inclusion_tag

      在cnblog/blog/目录下创建templatestags目录,再创建my_tags.py文件。

    (1)先快速创建简单tag,简单tag:只带一个参数,返回经过处理的字符串

      Django提供了一种simple_tag方法来快速创建类似这样的tag。

    from django import template
    
    register = template.Library()
    
    # 乘法的函数
    @register.simple_tag
    def multi_tag(x,y):
        return x*y
    

      修改article_detail.html,load用来载入一个过滤器或者tag, 在这里引入my_tags:

    {% extends "base.html" %}
    
    {% block content %}
        {% load my_tags %}
    
        {% multi_tag 3 9 %}
    {% endblock %}
    

      显示效果如下所示:

      

    (2)创建inclusion tag

      样式和数据结合为一个整体的时候可以考虑使用inclusion_tag.

    my_tags.py:

    from django import template
    from django.db.models import Count
    from blog import models
    
    register = template.Library()
    
    # 乘法的函数
    @register.simple_tag
    def multi_tag(x,y):
        return x*y
    
    @register.inclusion_tag("classification.html")
    def get_classification_style(username):
        user = models.UserInfo.objects.filter(username=username).first()
        blog = user.blog
    
        cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")) 
            .values_list("title", "c")
    
        tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")) 
            .values_list("title", "c")
    
        date_list = models.Article.objects.filter(user=user).extra(
            select={"y_m_date": "date_format(create_time, '%%Y-%%m')"}) 
            .values("y_m_date").annotate(c=Count("nid")).values_list("y_m_date", "c")
        return {"username": username, "blog": blog, "cate_list": cate_list, "tag_list": tag_list, "date_list": date_list}

     将base.html中左侧边栏的面板代码内容取出,放置于classification.html中:

    base.html:

    <body>
    <div class="header">
        <div class="content">
            <!--站点标题-->
            <p class="title">
                <span>{{ blog.title }}</span>
                <a href="" class="backend">管理</a>
            </p>
        </div>
    </div>
    
    <div class="container">
        <div class="row">
            <div class="col-md-3">
                <!--添加bootstrap面板-->
                {% load my_tags %}
                {% get_classification_style username %}  
            </div>
            <div class="col-md-9">
                {% block content %}
    
                {% endblock %}
            </div>
        </div>
    </div>
    
    </body>

     classification.html:

    <div>
        <div class="panel panel-warning">
            <div class="panel-heading">我的标签</div>
            <div class="panel-body">
                {% for tag in tag_list %}
                    <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p>
                {% endfor %}
            </div>
        </div>
        <div class="panel panel-danger">
            <div class="panel-heading">随笔分类</div>
            <div class="panel-body">
                {% for cate in cate_list %}
                    <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p>
                {% endfor %}
            </div>
        </div>
        <div class="panel panel-success">
            <div class="panel-heading">随笔归档</div>
            <div class="panel-body">
                {% for date in date_list %}
                    <p><a href="/{{ username }}/archive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p>
                {% endfor %}
            </div>
        </div>
    </div>
    

      修改article_detail视图函数:

    def article_detail(request, username, article_id):
    
        # context = get_classification_data(username)
        # return render(request, "article_detail.html", context)
    
        return render(request, "article_detail.html", locals())
    

    三、文章详情页渲染的标签字符串转义

      Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。

    1、article_detail视图函数中应拿到文章对象传入模板中

    def article_detail(request, username, article_id):
        user = UserInfo.objects.filter(username=username).first()
        blog = user.blog
        article_obj = models.Article.objects.filter(pk=article_id).first()
    
        return render(request, "article_detail.html", locals())
    

    2、模板语法一旦检查到标签字符串都会进行转义

      首先需要确认网站文章内容保存的并不是一个文本,而是一堆标签字符串。这样编辑文章时才会有各种各样的样式。

      将文章内容直接传进模板中。

    {% extends "base.html" %}
    
    {% block content %}
        <h3 class="text-center">{{ article_obj.title }}</h3>
        <div class="cont">
            {{ article_obj.content }}
        </div>
    {% endblock %}
    article_detail.html

      但是直接复制网站的html源代码进文章内容中,显示是不正确的。

      

      如上所示:将<h1>hello</h1>存进数据库,当服务器传给浏览器的时候,却变成了&lt;h1&gt;hello&lt;/h&gt;,浏览器按特殊符号渲染,因此显示为<h1>hello</h1>。

      

      由此可见,模板语法一旦检查到标签字符串都会进行转义。

    3、在Django中关闭HTML的自动转义

      如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。比如:

    <p>这行代表会被自动转义</p>: {{ data }}
    <p>这行代表不会被自动转义</p>: {{ data|safe }}

      其中第二行我们关闭了Django的自动转义。
      我们还可以通过{%autoescape off%}的方式关闭整段代码的自动转义,比如下面这样:

    {% autoescape off %}
        Hello {{ name }}
    {% endautoescape %}
    

      

  • 相关阅读:
    Python randrange() 函数
    200行Python代码实现2048
    select默认下拉箭头改变、option样式清除
    图片垂直居中
    去除select边框和三角-----appearance:none
    原生 js 实现点击按钮复制文本
    This dependency was not found: * !!vue-style-loader!css-loader?……解决方案
    vue项目启动时将localhost替换成指定ip地址
    安装cnpm
    vue 项目要使用的库
  • 原文地址:https://www.cnblogs.com/xiugeng/p/9424825.html
Copyright © 2011-2022 走看看