zoukankan      html  css  js  c++  java
  • 博客项目——〇四 个文章页面设计

    下面我们来做一下显示文章内容的页面。先分析一下博客园页面布局是怎么样的

    页面布局

     刨去一些细节上的内容我们先不管,大概整体布局是这样的

     其实整体效果也可以使用上一章节里的基础母版,只做page-main这个block就可以了

    文章内容

    在这个页面中 文章的获取其实还是比较简单的,我们先看一看这个文章内容是怎么获取的

    因为在我们可以直接通过url访问一篇文章,这种是最直接的访问方法,其他用a标签的访问也相当于这个方式。我们看一下这个url的结构

    https://www.cnblogs.com/yinsedeyinse/p/13052827.html

    也就是用户/文章/文章id的形式,所以我们对url的定义就是这样的

    url(r'(w+)/article/(d+)/$',views.article_detial), 

    正则匹配的的一个字段就是username,这个用户名是被访问blog站点的作者,不是登录的用户;第二个字段用了d,也就是说文章id都是以数字形式存在的。直接匹配数字就可以了。 

    ORM流程

    article = models.Article.objects.filter(pk=1).first()                #获取id=1的article对象
    
    text = article.articledetail.content

    我们的article表和articledetail是通过一个外键关联的,用上面的方法就可以拿到文章里的内容。

    内容的渲染

    有一点要注意的,因为我们在编辑文章内容时是带有一定样式的,其实我们在数据库里存的应该都是html样式的字符串,如果要把这些字符串按要求的标签样式显示出来,就要记得在渲染的时候用safe这个tag

    <div>
        <h1>{{article.title}}</h1>
        <p>{{article.articledetail.content|safe}}</p>
    </div>

    这样就可以显示出我们需要的效果(可以直接从博客园里复制一片文章的div到数据库里,然后显示出来)。

    点赞功能

    下面是这一章第一个重要的地方:点赞。我们可以注意一下,在一般的网页中的点赞和踩都是局部刷新的,也就是用AJAX的方法实现的。我们下面一步步把这个效果实现出来

    前端的构造(DIV)

    简单的操作,我们把博客园里的点赞部分可以直接超过来

     复制的时候要注意把图片和样式一并拿到。

    整个div是这样的

    <!-- 点赞踩灭开始 -->
    <div id="div_digg">
        <div class="diggit action">
            <span class="diggnum" id="digg_count">{{article.up_count}}</span>
        </div>
        <div class="buryit action">
            <span class="burynum" id="bury_count">{{article.down_count}}</span>
        </div>
        <div class="clear"></div>
        <div class="diggword" id="digg_tips">
        </div>
        <div class="clear"></div>
    
        <div class="diggword" id="digg_tips" style="color: red;"></div>
    </div>
    <!-- 点赞踩灭结束 -->

     article就是我们在视图中通过id获得的article对象,里面包含了赞和踩的数量

    在这里因为赞和踩的流程是一样的,所以直接对action这个div做了一个点击事件然后关联了一个AJAX请求

     1 <script>
     2     $('#div_digg .action').click(function(){
     3 
     4         // 把点赞和踩灭放在一个function内,通过div的属性是否有diggit判定点击的是点赞还是踩灭
     5         var is_up = $(this).hasClass('diggit');
     6         var article_id = "{{article.pk}}";  //一定要注意在js内的模板替换字符串要用引号括起来
     7         var btn = $(this);
     8         console.log(article_id)
     9         $.ajax({
    10             url:"blog/up_down/",
    11             type:"POST",
    12             data:{
    13                 csrfmiddlewaretoken:'{{csrf_token}}',
    14                 is_up:is_up,
    15                 article_pk:article_id
    16                 },
    17 
    18             success:function(data){
    19                 console.log(data)
    20                 if(data.state)
    21                 {
    22                 btn.text(parseInt(btn.text())+1);
    23                 
    24                 }
    25                 else
    26                 {
    27                 $('#digg_tips').text(data.msg);
    28                 }
    29                 
    30                 }
    31             })
    32         })
    33 </script>

    可以注意一下思路,我们在点击了一个div以后判定一下里面有没有一个diggit属性(is_up),如果有点击的就是赞,否则就是踩。AJAX携带的数据里只有一个is_up和一个当前文章的id,再看一下Ajax请求对应的视图

     1 from django.db.models import F
     2 import json
     3 def up_down(request):
     4     print('in up_down')
     5     ret={'state':False}
     6 
     7     article_pk = request.POST.get('article_pk')
     8     #因为用get方法得到的is_up为一个为true的字符串,我们写到数据库里的必须为一个布尔量,要用json反序列话一下
     9     is_up = json.loads(request.POST.get('is_up'))  
    10 
    11     user = request.user
    12     article = models.Article.objects.get(pk=article_pk)
    13 
    14     if not user:
    15         ret['msg'] = '请登录'
    16     else:
    17         try:
    18             models.ArticleUpDown.objects.create(user=user,article = article,is_up=is_up)
    19             models.Article.objects.filter(pk=article_pk).update(up_count=F('up_count')+1)
    20             ret['state'] = True
    21         
    22         except Exception as e:
    23             ret1 = models.ArticleUpDown.objects.get(user=user,article=article).is_up
    24             ret['msg'] = '已经赞过' if ret1 else "已经踩过"
    25 
    26     return JsonResponse(ret)

    整个流程还算清晰,还是有几点需要注意的

    1.通过request.POST.get()拿到的值是个字符串类型的数据(string),但是ArticleUpDown这个表里的is_up字段是个布尔量类型的数据,那么就不能直接写,就要用JSON反序列化一下。

    2.常规情况下在没登录的时候是不能点赞或踩灭的,所以要对request.user进行判断,看看当前是否有用户登录,但是未有用户登录是还是有user值的,只不过登录状态为anonymoususer,我们可以用下面的方式来判定用户登录的状态

    user.is_authenticated

    如果有正常用户登录,返回值就为True,否则就为False。

    3.ORM添加新数据的时候是先对UpDown表里添加数据,成功了以后再对Article表里添加赞或踩的数量,这里用到了一个F查询,忘记的话可以查一下以前的博客(点击查看)。如果操作成功的话就返回一个成功对应的状态字。

    4.因为最后显示赞的数量是通过ajax实现的,我们没有重新从数据库里拿数,只是做了个DOM操作。但是操作前还是要做一下判断,看看前面的ORM操作是否成功。

    5.实际情况中还有一个使用环境:自己是无法对自己的文章操作的。还应该加一个对作者和登录的用户名进行一下比对。但这里没有做,最后的视图代码中应该会有

    JS代码的静态文件

    我们前面的所有操作都是把js代码放在html文件中,但是这样操作不利于代码的复用。可是如果把这段代码放在一个js文件中,有些参数是需要render渲染的,还有一些标签的关联是怎么操作的呢?这时就需要把上面那段JS代码重构一下了。

    注意render函数的过程,是把整个HTML文件过一遍,对render函数来说,HTML文件就是一个字符串,函数在执行的过程中一遇到{{}}和{%%}的时候就把中间的字符串直接把参数中的字典里的数据套进去。但是导入的JavaScript标签

    <script src="/static/js/updown.js"></script>

    就直接按照字符串的形式过一遍,并不会把JavaScript文件里的{{}}替换掉

    我们把前面整个JavaScript代码段粘贴到一个新的js文件中,要改的地方有两点,也就是两个{{}}的地方

    1.现在这种csrf的方式不行,必须在HTML文件中通过下面的代码生成一个隐藏的div

    {%csrf_token%}

    然后把js中csrf中间件的部分修改成下面这样的

    csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(),

    2.在这个js文件中获取article_id的方法是这样的

    var article_id = "{{article.pk}}";  //一定要注意在js内的模板替换字符串要用引号括起来

    这里讲的是一个比较笨的方法:在html中直接做一个div,把需要的内容加到div的属性里,div可以隐藏,不过因为div里没有内容隐藏不隐藏关系不大

    <div class="info" article_id='{{article.nid}}' style="display:none ;"></div>

    然后在js中直接用attr获取属性就可以了

    var article_id = $('.info').attr('article_id');

    其他就不用改了。

    评论功能

     评论功能的实现比较复杂,我们在下一章详细来说(点击查看)。

  • 相关阅读:
    跳跃游戏1,2
    重叠子区间问题
    最长公共子序列问题
    由leetcode俄罗斯套娃信封问题到C++的sort()函数学习
    一道笔试题,做的很垃圾
    Spring boot框架快速入门
    Redis常用数据类型及其对应的底层数据结构
    Java 类加载机制及双亲委派模型
    Java面试高频知识点总结 part3
    Spring框架专题
  • 原文地址:https://www.cnblogs.com/yinsedeyinse/p/13170841.html
Copyright © 2011-2022 走看看