BBS - 文章详细页、点赞、踩灭
一、文章详细页
文章详细页:
1.链接:
<div><h5><a href="/blog/{{ article.user.username }}/articles/{{ article.pk }}">{{ article.title }}</a></h5></div>
2.url分配:
re_path('(?P<username>\w+)/articles/(?P<article_id>\d+)/$',views.article_detail),
# 注意放在上面,否则下面得会覆盖上面得!
re_path('(?P<username>\w+)/articles/(?P<article_id>\d+)/$',views.article_detail),
re_path('(?P<username>\w+)/$',views.homesite)
3.模板继承:
因为 homesite 与 article_detail 整体页面样式,一样,只有内容部分不一样!!
继承,只传样式,没数据,怎么办? (include_tag)
知识点:
1.inclue 没有盒子得概念,某一块html直接拿来用!
{% include 'menu.html' %}
2.extends 可重写,可复用,有盒子得概念,整个页面继承.
{% extends 'base.html' %}
3.自定义标签
/blog/templatetags/my_tags.py
from django import template
register = template.Library()
@register.simple_tag
def mul(x,y):
return x*y
4.include_tag (自定义标签生成了html)
# 将 模板与数据 结合起来 (如果写函数也可以传数据,但是将模板与数据分开了)
/templatetags/my_tags.py
{% load my_tags %}
{% get_menu username %}
@register.inclusion_tag('menu.html')
def get_menu(username):
...
return {} 返回字典 去渲染 menu.html
作用:
include_tag 能解决复用问题,数据重复问题; 既有数据处理,又有模板渲染!
# -*- coding:utf-8 -*- from django import template register = template.Library() @register.simple_tag def mul(x,y): return x*y from blog.models import * @register.inclusion_tag('menu.html') def get_menu(username): # 当前站点得用户对象 user = UserInfo.objects.filter(username=username).first() blog = user.blog # 查询站点所有每一个分类 以及 对应得文章数 分组!! from django.db.models import Count # 查询站点所有每一个分类 以及 对应得文章数 分组!! cate_list = Category.objects.filter(blog=blog).annotate(count = Count('article')).values('title','count') # 每一个标签以及对应得文章数 tag_list = Tag.objects.filter(blog=blog).annotate(count = Count('article')).values_list('title','count') # 查询每一个年月 日期 查询 统计 date_list = Article.objects.filter(user=user).extra(select={"create_ym":"DATE_FORMAT(create_time,'%%Y-%%m')"}).values('create_ym').annotate(c = Count('nid')).values_list('create_ym','c') return {'username':username,'cate_list':cate_list,'tag_list':tag_list,'date_list':date_list}
<div class="menu"> <div class="panel panel-info"> <div class="panel-heading">我的分类</div> <div class="panel-body"> {% for cate in cate_list %} <p><a href="/blog/{{ username }}/cate/{{ cate.title }}">{{ cate.title }}({{ cate.count }})</a></p> {% endfor %} </div> </div> <div class="panel panel-success"> <div class="panel-heading">我的标签</div> <div class="panel-body"> {% for tag in tag_list %} <p><a href="/blog/{{ 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 date in date_list %} <p><a href="/blog/{{ username }}/archive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p> {% endfor %} </div> </div> </div>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>homesite</title> {% load my_tags %} <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css"> <link rel="stylesheet" href="/static/css/article_detail.css"> <script src="/static/js/jquery-3.2.1.min.js"></script> <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script> <style type="text/css"> *{padding: 0;margin: 0;} .header{ width: 100%; height: 40px; background-color: #336699; line-height: 40px; font-size: 16px; color: white;} .header p{ margin-left: 15px;} </style> </head> <body> <div class="header"> <p class="title">{{ blog.title }}</p> </div> <div class='container'> <div class="col-md-3"> {% get_menu username %} </div> <div class="col-md-8"> {% block content %} {% endblock content %} </div> </div> </body> </html>
{% extends 'base.html' %} {% block content %} {% load my_tags %} <div class="article_list"> {% for article in article_list %} <div class="article_item"> <div><h5><a href="/blog/{{ article.user.username }}/articles/{{ article.pk }}">{{ article.title }}</a></h5></div> <div class="row"> <div class="col-md-9 desc"> <p>{{ article.desc }}</p> </div> </div> <div class="small"> 发布于 <span>{{ article.create_time|date:'Y-m-d' }}</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> {% endblock content %}
def homesite(request,username,**kwargs): # 当前站点得用户对象 user = UserInfo.objects.filter(username=username).first() if not user: return HttpResponse('404') # 当前站点对象 blog = user.blog # 查询当前站点对应得文章,以及分类,标签,日期归档得文章 if not kwargs: article_list = Article.objects.filter(user=user) else: condition = kwargs.get('condition') param = kwargs.get('param') if condition == 'cate': article_list = Article.objects.filter(user=user, category__title=param) elif condition == 'tag': article_list = Article.objects.filter(user=user, tags__title=param) else: year, month = param.split('-') article_list = Article.objects.filter(user=user).filter(create_time__year=year, create_time__month=month) return render(request,'homesite.html',locals())
{% extends 'base.html' %} {% block content %} <h3 class="text-center">{{ article.title }}</h3> <div class="content"> {{ article.articledetail.content|safe }} </div> <input type="hidden" id="hid_article_pk" value="{{ article.pk }}"> <div id="div_digg"> <div class="diggit digg"> <span class="diggnum" id="digg_count">{{ article.up_count }}</span> </div> <div class="buryit digg"> <span class="burynum" id="bury_count">{{ article.down_count }}</span> </div> </div> <div id="digg_word" class="pull-right"></div> {% csrf_token %} <script src="/static/js/article_detail.js"></script> {% endblock content%}
def article_detail(request,username,article_id): user = UserInfo.objects.filter(username=username).first() blog = user.blog article = Article.objects.filter(pk=article_id).first() return render(request,'article_detail.html',locals())
4.文章详细内容:
<h3 class="text-center">{{ article.title }}</h3>
<div class="content">
{{ article.articledetail.content|safe }}
</div>
为什么要加 safe?
{{ article.articledetail.content|safe }},告诉django不要转义!
django 框架会将标签转义!
库:
<h1>Hello world</h1>
django:
<h1>Hello world</h1>
浏览器渲染后:
<h1>Hello world</h1>
django 得模板问题:遇到标签转译为特殊字符,发送给客户端。
防止用户存一些 js 如果交给浏览器就会加载,实现攻击,恶意破环!
然而,就不应该让标签,不合法得类似<script>入库,后续beautifulSoup会学!
5.个人 站点 样式(皮肤)不一样:
<link rel="stylesheet" href="/static/theme/{{ blog.theme }}">
二、点赞、踩灭
注意点:
1.
在js中使用模板{{}} 加"", 不加""就当作变量了,找不到。
if("{{ request.user.username }}"){}
2.
ajax实现,两个按钮绑定一个点击事件。
前端:
var is_up = $(this).hasClass('diggit'); # true false
后台:
is_up = json.loads(request.POST.get('is_up')) # 变成 boolean 因为是str
3.
from django.db import transaction
try:
with transaction.atomic(): # 事务!同进退,数据同步!!
是点赞还是踩灭? 自+1 更新时 F 查询得应用
ArticleUpDown.objects.create(is_up=is_up,article_id=article_id,user_id=user_id)
if is_up:
Article.objects.filter(pk=article_id).update(up_count = F("up_count") + 1)
else:
Article.objects.filter(pk=article_id).update(down_count = F("down_count") + 1)
except Exception as e:
需要返回上一次得 点击情况:
res['state'] = False
res['first_operate'] = ArticleUpDown.objects.filter(article_id=article_id,user_id=user_id).first().is_up
4.code:
<script src="/static/js/article_detail.js"></script>
<input type="hidden" id="hid_article_pk" value="{{ article.pk }}"> <input type="hidden" id="hid_username" value="{{ request.user.username }}"> <div id="div_digg"> <div class="diggit digg"> <span class="diggnum" id="digg_count">{{ article.up_count }}</span> </div> <div class="buryit digg"> <span class="burynum" id="bury_count">{{ article.down_count }}</span> </div> </div> <div id="digg_word" class="pull-right"></div>
import json from django.http import JsonResponse from django.db.models import F def poll(request): is_up = json.loads(request.POST.get('is_up')) # 得变成 boolean article_id = request.POST.get('article_id') user_id = request.user.pk res = {'state':True} from django.db import transaction try: with transaction.atomic(): # 事务 ArticleUpDown.objects.create(is_up=is_up,article_id=article_id,user_id=user_id) if is_up: Article.objects.filter(pk=article_id).update(up_count = F("up_count") + 1) else: Article.objects.filter(pk=article_id).update(down_count = F("down_count") + 1) except Exception as e: res['state'] = False res['first_operate'] = ArticleUpDown.objects.filter(article_id=article_id,user_id=user_id).first().is_up return JsonResponse(res)
$('#div_digg .digg').click(function () { var username = $('#hid_username').val(); if(username){ var is_up = $(this).hasClass('diggit'); var article_id = $('#hid_article_pk').val(); var csrfmiddlewaretoken = $('input[name="csrfmiddlewaretoken"]').val(); $.ajax({ url:'/blog/poll/', type:'post', data:{ is_up:is_up, article_id:article_id, csrfmiddlewaretoken:csrfmiddlewaretoken }, success:function (data) { if(data.state){ // 赞或者灭 成功 if(is_up){ var val = parseInt($('#digg_count').text())+1; $('#digg_count').text(val) }else{ var val = parseInt($('#bury_count').text())+1; $('#bury_count').text(val) } }else{ // 重复操作 失败 console.log(data.first_operate); if(data.first_operate){ $('#digg_word').html('您已经推荐过').css({"color":"red","margin-right":"-111px",'margin-top':"75px"}) }else{ $('#digg_word').html('您已经反对过').css({"color":"red","margin-right":"-111px",'margin-top':"75px"}) } } } }) }else{ location.href = '/login/' } });
知识点:
1.js 注意事项:
if(){ # 什么时候为 true / false ?
}else{
}
1.
if([]){
alert(123)
}
弹, [] 空对象, object 对于对象 boolean 是真!!
2.
if({}){
alert(456)
}
弹, {} 空对象,object 对于对象 boolean 是真!
3.
if(""){
alert(789)
}
不弹
对于 js 除了""外,其它得都为对象,
4.
if("999"){
alert(789)
}
弹 有值就为 真
2.js与模板语言:
js 可以写模板语言{{}},但是要写到 html 里面。 "{{ }}" render 就可以渲染!
但是:写在静态文件中:
<script src="/static/js/test.js"></script>
不能使用 {{}} 模板语言!
alert("{{ name }}")
因为:没有任何过程去渲染!!
js是浏览器再发一次请求!
可以:
<input id="hid_name" type="hidden" value={{name}}>
js:
var val = $('#hid_name').val()