django框架之BBS项目之文章详情和点赞

Posted yb635238477

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了django框架之BBS项目之文章详情和点赞相关的知识,希望对你有一定的参考价值。

内容回顾
    1. 个人博客主页
        1. 分类展示
            - 文章分类(2)
                文章(Article)表和分类(Category)表
                1. 先找这个人的博客有哪些文章分类
                2. 每个文章分类下的文章总数
                3. 基于对象的查询 category_obj.article_set.all().count()
                
            - 文章标签
                文章(Article)表和标签(Tag)表
                1. 先找这个人的博客有哪些文章标签
                2. 每个文章标签下的文章总数
                3. 基于对象的查询 tag_obj.article_set.all().count()
            - 日期归档
                1. mysql日期格式化函数          --> MySQL内置的那些函数
                   DATE_FORMAT(字段,‘格式‘)    --> sqlite语法:strftime(‘格式‘, ‘字段‘)
                   
                2. Django ORM执行原生SQL语句的方式:
                    1. .extra()
                        ret = models.Article.objects.all().extra(
                            select={"create_ym": "DATE_FORMAT(create_time, ‘%%Y-%%m-%%d‘)"}
                        )
                        # models.Article.objects.all()  --> [ArticleObj1, ArticleObj2, ...]
                        # .extra(select={"create_ym": "DATE_FORMAT(create_time, ‘%%Y-%%m-%%d‘)"})
                        #     --> ArticleObj1.create_ym
                    2. 类似pymysql的用法
                        # 更高灵活度的方式执行原生SQL语句
                        from django.db import connection  # 连接
                        # 从连接中获取光标,等待输入命令
                        cursor = connection.cursor()
                        # 光标执行SQL语句
                        cursor.execute("""SELECT DATE_FORMAT(create_time, ‘%Y-%m‘) FROM blog_article;""")
                        # 取出SQL语句执行后的结果
                        ret = cursor.fetchall()
                        print(ret)
                
                3. 使用ORM按照年月分组,分别统计出年月的的文章数
                    archive_list = models.Article.objects.filter(user=user_obj).extra(
                        select={"y_m": "DATE_FORMAT(create_time, ‘%%Y-%%m‘)"}
                    ).values("y_m").annotate(c=Count("id")).values("y_m", "c")
                                
        2. 4合1路由实现分类访问文章
            1. URL设计
                注意事项:Django的urls.py中分组命名和分组匹配不能混合使用!!!
                
            2. 视图中利用args去判断    
                
    3. 补充
        1. QuerySet是惰性求值的
        2. debug-tool-bar工具的使用:https://www.cnblogs.com/liwenzhou/p/9245507.html

 

今天我们实现文章的详情页面,就是当我们进入个人博客页面后,点击谋篇具体的文章,展示相应的文章详情。

我们就需要给文章详情配url,blog/yangbo/p/1,

所以a标签的地址就配成:

 <a href="/blog/{{ user_obj.username }}/p/{{ article.id }} "><h4 class="media-heading">{{ article.title }}</h4></a>

url.py文件就配成:

url(r^blog/(w+)/p/(d+)/$,views.article),

视图函数:

def article(request,username,id):
    ‘‘‘
    文章详情页面
    :param request: 请求对象
    :param username:用户名
    :param id:id
    :return:
    ‘‘‘
    user_obj = models.UserInfo.objects.filter(username=username).first()
    blog = user_obj.blog
    category_list = models.Category.objects.filter(blog=blog)
    tag_list = models.Tag.objects.filter(blog=blog)
    article_list = models.Article.objects.filter(user=user_obj)
    archive_list = models.Article.objects.filter(user=user_obj).extra(
        select={y_m: DATE_FORMAT(create_time,"%%Y-%%m")}
    ).values(y_m).annotate(c=Count(id)).values(y_m, c)
    article_obj = models.Article.objects.filter(id = id).first()
    print(article_obj.title)
    return render(request,article.html,{
        article_obj:article_obj,
        article_list: article_list,
        user_obj: user_obj,
        category_list: category_list,
        tag_list: tag_list,
        archive_list: archive_list
    })

这样我们发现页面有很多重复的代码:因为每个页面都基本一样只是文章展示区不一样,所以我们就想到了模板将一样的地方放在一个模板里。

新建一个html文件,将所有一样的代码放在base.html里,在模板页面中不一样的地方定义一个块

{% block page-main %}

{% endblock page-main %}

然后再子页面中:

{% extends ‘base.html‘ %}
{% block page-main %}
写不一样的代码,这里的代码会替换base模板中block的内容。
{% endblock %}

在视图函数中,不管是在个人博客的视图函数还是在文章详情的试图函数中,我们都会看到很多重复的代码,首先我们想到的是把重复的代码写成一个函数,用这个函数的时候,调用就可以了,但是,如果这个函数除了问题,那么调用它的试图函数就不会执行页面就不会展示。这块有点难理解,可以复习一下模板和组件那块地内容!!!

这时候我们想到了组件:

在app的文件夹下创建一个名为templatetags(名字必须是templatetags)的package,在里面创建一个py文件,

在文件里必须写上这两行代码:

from django import template
# 实例必须叫这个名字
register = template.Library()

然后再写组件的内容:

from django import template
from blog import models
from django.db.models import Count

#实例必须叫这个名字
register = template.Library()

@register.inclusion_tag(filename=left_menu.html)
def left_con(username):
    print(username)
    user_obj = models.UserInfo.objects.filter(username=username).first()
    print(user_obj)
    blog = user_obj.blog
    category_list = models.Category.objects.filter(blog=blog)
    tag_list = models.Tag.objects.filter(blog=blog)
    archive_list = models.Article.objects.filter(user=user_obj).extra(
        select={y_m: DATE_FORMAT(create_time,"%%Y-%%m")}
    ).values(y_m).annotate(c=Count(id)).values(y_m, c)
    return {
        user_obj:user_obj,
        category_list: category_list,
        tag_list: tag_list,
        archive_list: archive_list
    }

bas.html页面中应该这样引入组件:

  {% load left_memu %}
{
% left_con user_obj.username %}

base.html中引入left_memu函数,并且将user_obj.username传给这个left_con函数,left_con将返回值传给left_menu.html页面渲染,渲染完了之后,然后在把整个left_menu.html页面在base.html页面中渲染。

接下来就是给文章详情添加点赞的功能:

当我们点击点赞或反对时 ,我们应该拿到的是文章的id,和用户名的id,然后把这些数据传给后端,后端在数据库中做记录,然后将数据在页面中渲染。

html代码:

<!--点赞开始-->
    <div id="div_digg">
        <div class="diggit digg">
            <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
        </div>
        <div class="buryit digg">
            <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
        </div>
        <div class="clear"></div>
        <!--提示信息-->
        <div class="diggword" id="digg_tips">

        </div>
    </div>
<!--点赞结束-->
$(.digg).click(function () {
            if(!{{ request.user.username }}){ //如果不加引号,就会被当成是变量
                //先判断有没有登陆,没有登陆就跳转到登陆页面
                location.href = /login/?next={{ request.get_full_path }}
            }
            //已经登陆就可以点赞或反对
            var userid = {{ request.user.id }};
            var articleid = {{ article_obj.id }};
            //区分点赞还是反对
            var isup = $(this).hasClass(diggit);
            // 像后端发请求
            $.ajax({
                url:/up_down/,
                type:post,
                data:{
                    csrfmiddlewaretoken:$([name="csrfmiddlewaretoken"]).val(),
                    userid:userid,
                    articleid:articleid,
                    isup:isup,
                },
                success:function (res) {
                    if(res.code!==0){
                        //只需要把错误提示显示出来就可以
                        $(.diggword).text(res.msg)
                    }else{
                        //1.更新点赞数或反对数
                        if(isup){
                            //点赞数加一
                            var $UpSpan = $("#digg_count");
                            $UpSpan.text(+$UpSpan.text()+1);
                            $(.diggword).text(res.msg)
                        }else{
                            // 反对数加一
                            var $downSpan = $("#bury_count");
                            $downSpan.text(+$downSpan.text()+1);
                            // 打印提示信息 
                            $(.diggword).text(res.msg)
                        }
                    }
                }
            })
        });

views代码:

def up_down(request):
    if request.method == POST:
        print(request.POST)
        res={code:0}
        userid = request.POST.get(userid)
        articleid = request.POST.get(articleid)
        isup = request.POST.get(isup)
        isup = True if isup.upper() == TRUE else False
        # 5. 不能给自己点赞
        is_own_article= models.Article.objects.filter(user_id=userid,id=articleid).first()
        print(is_own_article)
        if is_own_article:
            res[code] = 1
            res[msg] = 不能给自己点赞或反对
        else:
            # 3.同一个人只能给同一篇文章点赞一次
            # 4. 点赞和反对两个只能选一个
            # 判断一下 当前这个人和这篇文章在点赞表里有没有记录
            is_exit = models.ArticleUpDown.objects.filter(user_id=userid,article_id=articleid).first()
            # 如果存在
            if is_exit:
                res[code] = 1
                # 表示已经点赞过
                if is_exit.is_up == True:
                    res[msg] = 已经点赞过了
                # 表示已经反对过
                else:
                    res[msg] = 已经反对过了
            else:
                from django.db import transaction
                from django.db.models import Count, F
                  # 事务操作
                with transaction.atomic():
                    # 1.先创建点赞记录
                    models.ArticleUpDown.objects.create(user_id=userid,article_id=articleid,is_up=isup)
                    # 2.在更新文章表
                    if isup:
                        # 点赞数加1
                        models.Article.objects.filter(id=articleid).update(up_count=F(up_count)+1)
                        res[msg] = 点赞成功
                    else:
                        #反对数加1
                        models.Article.objects.filter(id=articleid).update(down_count=F(down_count)+1)
                        res[msg] = 反对成功
        return JsonResponse(res)

 


























































以上是关于django框架之BBS项目之文章详情和点赞的主要内容,如果未能解决你的问题,请参考以下文章

django框架之BBS项目之个人博客页面

DAY87-BBS项目 数据库设计与简单登陆验证码

BBS项目之点赞点踩功能

Django训练项目之BBS(博客项目)

bbs项目三

Django 项目试炼blog -- 文章详情页1 -- 点赞功能