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)

原文地址:https://www.cnblogs.com/yb635238477/p/9495467.html

时间: 2024-11-10 11:13:58

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

django框架之BBS项目之评论功能

内容回顾    1. BBS项目 CMS        1. 登录            1. form组件            2. auth模块            3. 验证码        2. 注册            1. form组件                1. 生成html代码                    直接for循环form_obj,就能够遍历所有字段                2. 验证                    1. 默认的那些验证

Django框架的安装,项目创建

目录 Django框架的安装,项目创建 方法安装 Django版本选择 1.11.21(最新LTS版) django管理目录 命令行创建项目 django项目 命令行启动 (必须在项目文件下执行) pychrm创建项目 pychrm启动项目 配置文件相关设置(重启生效) Django框架的安装,项目创建 方法安装 Django版本选择 1.11.21(最新LTS版) django管理目录 mysite/ ├── manage.py # 管理文件 └── mysite # 项目目录 ├── __i

Python Django框架实现商城项目源码加设计文档和注释

Python Django框架实现商城项目源码加设计文档和注释 链接:https://pan.baidu.com/s/1yN2iBgx3zmpTkoY8u1LWRg 提取码:lfsx 非常完整的django项目源码,分享给撸友们,不管是学习还是深造,都是可以学习借鉴的!! 原文地址:https://www.cnblogs.com/zyxlovesjy/p/12115491.html

Django框架学习----视图与模板(详情页的上下篇文章跳转跳转)

我们实现首页到详情页的跳转之后,接下来就是实现详情的上下篇文章的跳转 第一步:挑选按钮 把选中的按钮复制到我们的detail页面里面,并用一个div包含起来,如下图: 在上图中我定义了两个变量,他现在是不存在的,我们需要在views,py里面把这两个变量赋值之后并且映射过来.如下图: 写好之后重启一下你的项目,你的详情页就拥有了上下篇文章跳转功能了 原文地址:https://www.cnblogs.com/humiao-0626/p/12662555.html

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

url #文章详情页 re_path(r'(?P<username>\w+)/article/(?P<article_id>\d+)/$',views.article), # 点赞 path('up_down/', views.up_down), views from django.db.models import F def up_down(request): sign = request.POST.get('sign') sign = json.loads(sign) # 前端

一 Django框架介绍——用pycharm创建Django项目

Django框架介绍 Django是一个开放源代码的Web应用框架,由Python写成.采用了MVC的软件设计模式,即模型M,视图V和控制器C.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是CMS(内容管理系统)软件.并于2005年7月在BSD许可证下发布. 这套框架是以比利时的吉普赛爵士吉他手Django Reinhardt来命名的. 更多Django框架http://code.ziqiangxuetang.com/django/django-qrcode.htm

BBS - 文章详情页

一. 文章详情页的设计和数据构建 url.py # 文章详情页 re_path('^(?P<username>\w+)/articles/(?P<article_id>\d+)$', views.article_detail), # \w+:数字和字母 views.py def get_query_data(username): # 查询相关的数据,获取分类的数据 ''' 由于数据很多个地方需要用到,所以可以解耦出来,单独写一个函数 :param username: :return

Django学习之实现文章详情页面的跳转

1.由于不支持博客首页到文章详情页的跳转,只能打开第一篇文章的详情页 2.所以需要做以下工作: 设计文章详情页的url,完善视图函数逻辑,实现首页跳转 /blog/detail =>不能指定某一篇文章 /blog/detail/1 => 博客唯一id唯1的文章 /blog/detail/2 => 博客唯一id唯2的文章 /blog/detail/3 => 博客唯一id唯3的文章 /blog/detail/...... 获取URL路径参数:<> 页面跳转:href指定ht

Django框架基础

Django基础-Lesson1 web框架概念 框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统. 对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端.  socket模拟服务端 最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回. 如果要动态生成HTML,就需要把上述步骤自己来实现.不过,接受HTTP