第六十九天 BBS项目之五 js与模板语法 inclusion_tag实操,文章详情,点赞点踩

一、昨日内容回顾

# 1 首页文章的渲染
	-模板语法的for循环
    -bootstrap的媒体组
    -显示头像: articel.blog.userinfo  有可能没有 :在admin中建立关系
    	-注册---》申请开启博客功能
    -图标库
    	-font-awesome-4.7.0
        
# 2 个人站点样式
	-头部导航栏
    -左侧筛选:3个面板
    -右侧文章列表:首页文章列表差不多
    
    -使用了模板继承---》base.html----》尽量多的写block
# 3 个人站点左侧 标签,分类,随笔档案的渲染
	-查询出标签id,名字,标签下的文章数
    -查询出分类id,名字,分类下的文章数
    -查询出时间名字,时间下的文章数
    
    -查分类id,名字,当前博客下的----》单表查询+过滤
    -查分类id,名字,当前博客下的,分类下的文章数---》分组  group by
    selcet category.id,category.name,count(article.id) as c from category,article where category.id=article.cagegory and category.blog=2 group by category.id; Category.object.filter(blog=user.blog).values('id').annotate(c=Count(articel__id)).values('id','name','c')

    
# 4 左侧点击过滤
	-设计路由
    	-按标签过滤:/lqz/tag/标签id号.html
        -按分类过滤:/lqz/category/分类id号.html
        -按时间过滤:/lqz/archive/202209.html
    -三个路由归一
    	re_path('^(?P<name>\w+)/(?P<type_name>tag|category|archive)/(?P<condition>\d+).html', views.site),

    -视图函数,统一用site视图函数
    	-

### 扩展作业
# 原来轮播图使用模板语法渲染的
# 轮播图使用ajax渲染
-当页面加载完成发送ajax请求

    $(function () {
       $.ajax({
           url:'/get_banner/',
           type:'get',
           success:function (data){
               console.log(data)
               // {code:100,msg:成功,data:[{id:1,img:/banner/bannner1.jpg,name:'asdf',link:'/login/'},{id:1,img:/banner/bannner1.jpg,name:'asdf',link:'/login/'}]}
               // 通过dom操作,把img地址,放到 轮播图img的src中即可
           }
       })
    })

def get_banner(request):
    res = Banner.objects.all().values('id', 'img', 'name')[:2]
    # 如果这里用JsonResponse序列化不了,把res转成列表套字典的形式
    return JsonResponse({'code': 100, 'msg': '成功', 'data': res})
"""
$(function ()就是文件加载完成的意思
windows.onload也行
"""

二、模板和模板语法的区别

# 模板语言---》模板---》不是前端页面---》区分开
-django中:模板语法,dtl:django template language,django自己设计,写的
-flask中:模板语法:jinja2,第三方
-java: jsp  理解为:java web 的模板语言
-php:  php  <? php语言 >

-xx.html 中写了python代码,这个不是前端页面,叫模板
"""
个人的理解是前端就是用前端自己的语言写的。模板的渲染是后端完成的,所以前端中的python语言理论上为模板
"""

views.py中
def test(request):
    return render(request, 'test.html',
                  context={'name': "lqz", 'age': 19, 'a': 'a', 'l': [1, 2, 3], 'd': {'name': 'lyf', 'age': 40}})
——————————————————————————————————————————————————
test.html中
<script>
    // 可以在js代码用模板渲染,但是只能用数字,字符串(加引号),列表  不能用元组,字典,对象   test
    // 后端模板中得name给js的name
    var name ='{{name}}'
    // 后端模板中得age给js的age
    var age = {{ age }}
    var l= {{ test }}
    //var d={'name': 'lyf', 'age': 40}

    console.log(age)
    console.log(name)
    console.log(l)
    //console.log(d)

    $('h2').html(age)

    // 把js的变量l,给python的视图函数中得l

</script>
"""
1.对于结果是数字的,就没有问题
2.对于结果是字符串的
var name ={{name}} 本质上是
var name = lqz   所以会报错
var name ='{{name}}'   就得自己加上引号
3.不能用元组,字典,对象   test
"""

三、左侧使用inclusion_tag方案实现(第58天也有)

首先是inclusion_tag的作用,是可以让一部分的网页作为可以用模型渲染的函数调用
# 自定义标签
-第一步:在app中创建包:templatetags
-第二步:在包下新建py文件:如:my_tags.py
-第三步:在py文件中导入
from django import template
第四步:实例化得到对象
register = template.Library()
第五步:使用register装饰函数
@register.inclusion_tag('left.html', name='left')
def left(name):
	return {}  # 字典的数据可以在left.html中使用
 -第六步:在想引入inclusion_tag使用---》base.html 的栅格左侧占2个栅格的位置
{% load my_tags %}
{% left  name%}
may_tag文件中

from django import template
from blog import models
from django.db.models.functions import TruncMonth, TruncDay, TruncYear, TruncHour
from django.db.models import Avg, Max, Min, Count

register = template.Library()


@register.inclusion_tag('left.html', name='left')
def left(name):
    user = models.UserInfo.objects.filter(username=name).first()
    tag_res = models.Tag.objects.filter(blog=user.blog).values('id').annotate(c=Count('article__id')).values_list('id', 'name', 'c')
    category_res = models.Category.objects.filter(blog=user.blog).values('id').annotate(c=Count('article__id')).values_list('id', 'name', 'c')
    data_res = models.Article.objects.filter(blog=user.blog).annotate(year_month=TruncMonth('create_time')).values('year_month').annotate(c=Count('id')).values_list('year_month', 'c')
    print(tag_res)
    print(category_res)
    print(data_res)
    return {'tag_res': tag_res, 'category_res': category_res, 'data_res': data_res,'user': user}  # 返回的字典,可以在left.html中使用
left 文件中(部分)

<div class="panel panel-success">
    <div class="panel-heading">
        <h3 class="panel-title">我的标签</h3>
    </div>
    <div class="panel-body">
        <div>
            {% for tag in tag_res %}
                <div>
                    <a href="/{{ user.username }}/tag/{{ tag.0 }}.html">
                        <sapn>{{ tag.1 }}</sapn>
                        <span>{{ tag.2 }}</span>
                    </a>
                </div>
            {% endfor %}
        </div>
    </div>
</div>
具体使用在了base.html中
<div class="container-fluid">
    <div class="row">
        <div class="col-md-2">
            {% load my_tag %}
            {% left name %}
        </div>
        <div class="col-md-10">
            {% block article %}

            {% endblock %}
        </div>
    </div>
</div>

"""
总结:
1.templatetags文件名千万别写错
2.'left.html'表示拿来作为模块的文件,name='left'可以不写,默认就是下面的函数名
@register.inclusion_tag('left.html', name='left')
def left(name):
	return {}  # 字典的数据可以在left.html中使用
3缺啥参数就传啥参数,name比较特殊因为在渲染base的时候name就已经被site获取到了,就可以利用
{% left name %}传输给left
"""

四、文章详情页

name比较复杂
首先name在第一次被传入是在site中
之后点击用户的名字就等同于访问了site,并将name传给了site
views的site函数中,name被传入了参数,又用locals还给了site网页,所以site.html可以直接使用{{name}}
点击<a href="/{{ name }}/articles/{{ article.id }}.html">访问了article_detail
之后就接收了name
# 搭建页面的时候需要什么就传入什么

五、点赞点踩样式

    <script>
        // 点赞点踩写成1个事件
        $(".up").click(function () {
            var up = $(this).hasClass('diggit')  // 判断点击的这个标签有没有diggit类,如果有就是true,up是true表示点赞,否则表示点踩
            $.ajax({
                url: '/up_and_down/',
                type: 'post',
                data: {
                    // 谁给那篇文章点赞或点踩---》谁可以不传,当前登录用户就是点赞人
                    //article_id:$('h2').attr('name') // 方式1:把文章id,放在某个标签中,使用jq取到id
                    article_id: '{{ article_detail.id }}',
                    up_or_down: up,
                    csrfmiddlewaretoken: '{{ csrf_token }}'
                },
                success: function (data) {
                    $('#digg_tips').html(data.msg)
                    if(data.code==100){
                        //
                    }


                }
            })

        })
    </script>
——————————————————————————————————————————————————————————————————
import json
from django.db.models import F
from django.db import transaction
def up_and_down(request):
    res = {'code': 100, 'msg': '点赞成功'}
    # 1 判断用户是否登录
    if request.user.is_authenticated:  # 只要登录了就是当前登录用户,如果没登录就是匿名用户
        # 2 取出文件id,用户id,点赞或点踩
        article_id = request.POST.get('article_id')
        up = json.loads(request.POST.get('up_or_down'))  # 坑:up是什么类型?<class 'str'>
        # 把str类型的up:'true'--->转成---》python中布尔类型:up:True

        # 3 根据是点赞还是点踩向点赞点踩表中存数据
        count = UpAndDown.objects.filter(user=request.user, article_id=article_id).count()
        if count:
            res['code'] = 101
            res['msg'] = '您已经点过了'
            return JsonResponse(res)
        else:
            with transaction.atomic(): #开启事务,保证,插入点赞点踩表和文章表增加1 ,要么都成功,要么都失败
                UpAndDown.objects.create(user=request.user, article_id=article_id, is_up=up)
                # 4 在aritlcle表中点赞或点踩数+1

                if up:
                    Article.objects.filter(pk=article_id).update(up_num=F('up_num')+1)
                    res['msg'] = '点赞成功'
                else:
                    Article.objects.filter(pk=article_id).update(down_num=F('down_num') + 1)
                    res['msg'] = '点踩成功'


        return JsonResponse(res)
    else:
        res['code'] = 102
        res['msg'] = '您没有登录,请先 <a href="/login/">登录</a>'
        return JsonResponse(res)
——————————————————————————————————————————————————————————————————
"""
这里的第一个重点是    if request.user.is_authenticated:  # 只要登录了就是当前登录用户,如果没登录就是匿名用户
这里的第二个重点是     with transaction.atomic(): #开启事务,保证,插入点赞点踩表和文章表增加1 ,要么都成功,要么都失败!!!!!!!!!
"""
posted @   暧昧的花蝴蝶  阅读(6)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示