BBS-文章详情页、评论、评论树
1、简单的实现评论功能
article_detail.html,拿到数据 由路--给视图函数--写入数据库
<p>评论内容:</p>
<textarea name="" id="comment_content" cols="" rows=""></textarea>
<p>
<button class="btn btn-default comment_btn">提交评论</button>
</p>
url
path("comment/", views.comment),
--
<script>
$('.comment_btn').click(function () {
{#根评论#}
var pid='';
var content=$('#comment_content').val();
$.ajax({
url:'/comment/',
type:'post',
data:{ "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
'article_id':'{{ article_obj.pk }}','content':content ,'pid':pid},
success:function (data) {
console.log(data)
} })
})
---
def comment(request):
"""
提交评论视图函数
功能:
1 保存评论
2 创建事务
3 发送邮件
:param request:
:return:
"""
print(request.POST) article_id = request.POST.get("article_id")
pid = request.POST.get("pid")
content = request.POST.get("content")
user_id = request.user.pk
comment_obj=models.Comment.objects.create(user_id=user_id,article_id=article_id,content=content,parent_comment_id=pid)
评论之后--清空评论框
显示根评论的两种方法
1、render显示根评论
---
class="list-group
article_detail.html
<p>评论列表</p>
<ul class="list-group comment_list">
{% for comment in comment_list %}
<li class="list-group-item">
<div>
<a href=""># {{ forloop.counter }}楼</a>
<span>{{ comment.create_time|date:"Y-m-d H:i" }}</span>
<a href=""><span>{{ comment.user.username }}</span></a>
<a class="pull-right reply_btn" username="{{ comment.user.username }}"
comment_pk="{{ comment.pk }}">回复</a>
</div><div class="comment_con">
<p>{{ comment.content }}</p>
</div>
</li>
{% endfor %}
</ul>
2、ajax显示评论:es6 模板字符串
上一种方法评论后刷新才显示---用ajax评论就显示
success:function (data) {
console.log(data); var create_time = data.create_time;
var username=data.username;
var content=data.content; // 构建标签字符串 es6语法
var s = `
<li class="list-group-item">
<div> <span>${create_time}</span>
<a href=""><span>${username}</span></a> </div>
<div class="comment_con">
<p>${content}</p>
</div> </li>`; $("ul.comment_list").append(s);
def comment():
response={}
response['create_time']=comment_obj.create_time.strftime("%Y-%m-%d %X")
response['username']=request.user.username
response['content']=content
return JsonResponse(response)
根评论
{# 评论#}
<div class="comments list-group">
<p class="tree_btn">评论树</p>
<div class="comment_tree">
</div>
<p>评论列表</p>
<ul class="list-group comment_list">
{% for comment in comment_list %}
<li class="list-group-item">
<div>
<a href=""># {{ forloop.counter }}楼</a>
<span>{{ comment.create_time|date:"Y-m-d H:i" }}</span>
<a href=""><span>{{ comment.user.username }}</span></a>
<a class="pull-right reply_btn" username="{{ comment.user.username }}"
comment_pk="{{ comment.pk }}">回复</a>
</div> {% if comment.parent_comment_id %}
<div class="pid_info well">
<p>
{{ comment.parent_comment.user.username }}: {{ comment.parent_comment.content }}
</p>
</div>
{% endif %}
<div class="comment_con">
<p>{{ comment.content }}</p>
</div>
</li>
{% endfor %}
</ul>
<p>发表评论</p>
<p>昵称:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size=""
value="{{ request.user.username }}">
</p>
<p>评论内容:</p>
<textarea name="" id="comment_content" cols="" rows=""></textarea>
<p>
<button class="btn btn-default comment_btn">提交评论</button>
</p>
</div> <script>
$('.comment_btn').click(function () {
{#根评论#}
var pid='';
var content=$('#comment_content').val();
$.ajax({
url:'/comment/',
type:'post',
data:{ "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
'article_id':'{{ article_obj.pk }}','content':content ,'pid':pid},
success:function (data) {
console.log(data); var create_time = data.create_time;
var username=data.username;
var content=data.content; // 构建标签字符串 es6语法
var s = `
<li class="list-group-item">
<div> <span>${create_time}</span>
<a href=""><span>${username}</span></a> </div>
<div class="comment_con">
<p>${content}</p>
</div> </li>`; $("ul.comment_list").append(s); // 传回数据后,清空评论框中的内容
$('#comment_content').val('');
} })
})
</script>
3、子评论
--
--
// 回复按钮事件
$('.reply_btn').click(function () {
$('#comment_content').focus();
// 找父评论
var val='@'+$(this).attr('username')+'\n';
$('#comment_content').val(val)
})
提交子评论
根评论和子评论看是否点击回复
--
对样式进行改进
子评论对内容进行处理
清空pid
# indexOf()
定义和用法
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
语法
stringObject.indexOf(searchvalue,fromindex) # slice()
定义和用法
slice() 方法可从已有的数组中返回选定的元素。
语法
arrayObject.slice(start,end)
博客系统之render显示子评论
{% if comment.parent_comment_id %}
<div class="pid_info well">
<p>
{{ comment.parent_comment.user.username }}: {{ comment.parent_comment.content }}
</p>
</div>
{% endif %}
博客系统之Ajax显示子评论的思路
4、评论树
1、评论树简介
1、方式1:递归完成
2、方式2:评论树展示数据
2、评论树的请求数据
{# 评论#}
<div class="comments list-group">
<p class="tree_btn">评论树</p>
<div class="comment_tree">
</div>
{#-------评论树-------#}
<script> $.ajax({
url: "/get_comment_tree/",
type: "get",
data: {
article_id: "{{ article_obj.pk }}"
},
success: function (comment_list) {
console.log(comment_list); $.each(comment_list, function (index, comment_object) { var pk = comment_object.pk;
var content = comment_object.content;
var parent_comment_id = comment_object.parent_comment_id;
var s = '<div class="comment_item" comment_id=' + pk + '><span>' + content + '</span></div>'; if (!parent_comment_id) { $(".comment_tree").append(s);
} else {
$("[comment_id=" + parent_comment_id + "]").append(s);
}
})
}
})
</script>
视图函数
def get_comment_tree(request):
article_id=request.GET.get('article_id')
ret=list(models.Comment.objects.filter(article_id=article_id).values('pk','content','parent_comment_id'))
return JsonResponse(ret,safe=False)
-----
function (index, comment_object)
函数中两个参数对应下图中的,一个索引,循环的元素对象
博客系统之评论事务操作
# 事务 from django.db import transaction
with transaction.atomic():
comment_obj=models.Comment.objects.create(user_id=user_id,article_id=article_id,content=content,parent_comment_id=pid)
# 数据同步 F比较两个字段
models.Article.objects.filter(pk=article_id).update(comment_count=F('comment_count')+1)
博客系统之评论的邮件发送new
别人对你的博客评论或者对你的评论进行评论,博客发邮件给你
django中配置邮件
https://blog.csdn.net/xinxinnogiveup/article/details/78900811
https://code.ziqiangxuetang.com/django/django-send-email.html
1、settings配置
# 发送邮件
EMAIL_USE_SSL = True
# EMIAL_HOST = 'smtp.exmail.qq.com' # 如果是163 改成smtp.163.com
EMAIL_HOST = 'smtp.qq.com' # 如果是 163 改成 smtp.163.com
EMAIL_PORT = 465 # 163的端口号是25
EMAIL_HOST_USER = 'xxxxxxxx@qq.com' # 账号
EMAIL_HOST_PASSWORD = 'oXXXXXxxxxx' # qq邮箱的授权码而不是密码
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
# 发邮件
from django.core.mail import send_mail
from cnblog import settings
send_mail('您的文章%s新增了一条内容' % article_obj.title,content,
settings.EMAIL_HOST_USER,
["xxxxxxx@qq.com"])
加线程代码优化
# 发邮件
from django.core.mail import send_mail
from cnblog import settings
import threading
t=threading.Thread(target=send_mail,args=('您的文章%s新增了一条内容' % article_obj.title,content,
settings.EMAIL_HOST_USER,
["836342406@qq.com"]))
t.start()
整体代码
url
# 点赞
path('digg/',views.digg), path("comment/", views.comment),
# 获取评论树相关数据
path("get_comment_tree/", views.get_comment_tree), # media
re_path(r'media/(?P<path>.*)$',serve,{'document_root':settings.MEDIA_ROOT}), # 文章详情页
# re_path('(?P<username>\w)/(?P<article_id>\d+)$',views.article_detail),
re_path('^(?P<username>\w+)/articles/(?P<article_id>\d+)$', views.article_detail), # 关于个人站点的url
re_path("^(?P<username>\w+)/$", views.home_site), # home_site(reqeust,username="yuan")
#个人站点下的跳转
re_path('^(?P<username>\w+)/(?P<condition>tag|category|archive)/(?P<param>.*)/$', views.home_site),
# home_site(reqeust,username="yuan",condition='tag',param='python')
settings
LANGUAGE_CODE = 'en-us' # 时区选择
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True # 转换时区
# USE_TZ = True
USE_TZ = False # 发送邮件
EMAIL_USE_SSL = True
# EMIAL_HOST = 'smtp.exmail.qq.com' # 如果是163 改成smtp.163.com
EMAIL_HOST = 'smtp.qq.com' # 如果是 163 改成 smtp.163.com
EMAIL_PORT = 465
EMAIL_HOST_USER = '@qq.com' # 账号
EMAIL_HOST_PASSWORD = 'xxxxxx' # qq邮箱的授权码而不是密码
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
view视图
from django.shortcuts import render # Create your views here.
from django.shortcuts import render, HttpResponse,redirect # Create your views here.
# 用户认证模块
from django.contrib import auth
from django.http import JsonResponse
from blog.Myforms import UserForm
from blog.models import UserInfo
from blog import models
import json
from django.db.models import F
from django.db import transaction
from django.http import JsonResponse
from django.db.models import Avg, Max, Min, Sum, Count
from django.db import transaction
def login(request):
if request.method == 'POST':
response = {'user': None, 'msg': None}
user = request.POST.get('user')
pwd = request.POST.get('pwd')
# 读取验证码
valid_code = request.POST.get('valid_code')
# 回话跟踪技术,保存验证码
valid_code_str = request.session.get('valid_code_str')
# 如果书写的验证码和生成的验证码一致
# 不区分大小写---可以统一变成大写
if valid_code.upper() == valid_code_str.upper():
user = auth.authenticate(username=user, password=pwd)
if user:
auth.login(request, user) # request.user==当前登录对象
response['user'] = user.username
else:
response['msg'] = 'username or password error'
else:
response['msg'] = 'valid code error!'
return JsonResponse(response)
# ajax返回一个响应字符串
return render(request, 'login.html') # 随机验证码
def get_validCode_img(request):
from blog.utils.validCode import get_valid_Code_img
data = get_valid_Code_img(request)
return HttpResponse(data) def index(request):
article_list=models.Article.objects.all()
return render(request, 'index.html', locals()) def register(request):
# 实例化 form 对象 if request.is_ajax():
print(request.POST)
# 对传来的数据进行验证
form = UserForm(request.POST)
response = {'user': None, 'msg': None}
if form.is_valid():
response['user'] = form.cleaned_data.get('user')
# 注册成功要把数据添加进数据库
# 生成一条用户记录
user = form.cleaned_data.get('user')
pwd = form.cleaned_data.get('pwd')
email = form.cleaned_data.get('email')
avatar_obj = request.FILES.get('avatar')
# if avatar_obj:
# user_obj = UserInfo.objects.create_user(username=user, password=pwd, email=email, avatar=avatar_obj)
# else:
# user_obj = UserInfo.objects.create_user(username=user, password=pwd, email=email)
extra = {}
if avatar_obj:
extra["avatar"] = avatar_obj UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra) else:
print(form.cleaned_data)
print(form.errors)
response['msg'] = form.errors
# 返回给Ajax
return JsonResponse(response)
form = UserForm()
return render(request, 'register.html', locals()) def logout(request):
# request.session.flush()
auth.logout(request)
return redirect('/login/') def get_classification_data(username):
user_obj = models.UserInfo.objects.filter(username=username).first()
blog = user_obj.blog
cate_list = models.Category.objects.filter(blog=blog).values('pk').annotate(c=Count('article__title')).values_list(
'title', 'c')
tag_list = models.Tag.objects.filter(blog=blog).values('pk').annotate(count=Count('article')).values_list('title',
'count')
date_list = models.Article.objects.filter(user=user_obj).extra(
select={'y_m_date': "date_format(create_time,'%%Y-%%m')"}).values('y_m_date').annotate(
c=Count('nid')).values_list('y_m_date', 'c')
return {"blog": blog, "cate_list": cate_list, "date_list": date_list, "tag_list": tag_list} def home_site(request,username,**kwargs):
'''
个人站点视图函数
:param request:
:return:
'''
user_obj=models.UserInfo.objects.filter(username=username).first() # 判断用户是否存在
if not user_obj:
return render(request,'not_found.html')
blog = user_obj.blog
print(blog) # 当前用户或者当前站点所对应文章 # 方式一基于对象查询
# 作者和文章的关系---> 一对多(文章)
# article_list=user_obj.article_set.all()
# 方式二 基于双下划线 __ 跨表查询
article_list=models.Article.objects.filter(user=user_obj)
# 判断是否跳转到其他地方
# re_path("^(?P<username>\w+)/(?P<condition>tag|category|archive)/(?P<param>.*)/$", views.home_site),
if kwargs:
condition = kwargs.get("condition") # 标签\分类\归档
param = kwargs.get("param") # 具体的哪一个
if condition == "category":
article_list = article_list.filter(category__title=param)
elif condition == "tag":
article_list = article_list.filter(tags__title=param)
print(article_list)
else:
year, month = param.split('-')
print(year, month)
article_list = article_list.filter(create_time__year=year,create_time__month=month)
print(article_list) # 查询每一个分类名称以及对应的文章数
# annotate(聚合函数(关联表__统计字段)).values("表模型的所有字段以及统计字段")
# values('group by的字段')
# ret=models.Category.objects.values('pk').annotate(c=Count('article__title')).values('title','c')
# print(ret) # 查询当前站点的每一个分类名称以及对应的文章数
cate_list=models.Category.objects.filter(blog=blog).values('pk').annotate(c=Count('article__title')).values_list('title','c')
print(cate_list) # 每一个标签以及对应得文章数
tag_list=models.Tag.objects.filter(blog=blog).values('pk').annotate(count=Count('article')).values_list('title','count')
print('tag_list',tag_list) # 单表分组查询
# 查询当前站点每一个年月的名称以及对应的文章数
# 方式一
date_list = models.Article.objects.filter(user=user_obj).extra(
select={'y_m_date': "date_format(create_time,'%%Y-%%m')"}).values('y_m_date').annotate(
c=Count('nid')).values_list('y_m_date', 'c')
print(date_list) # 方式二
from django.db.models.functions import TruncMonth
#
# date_list=models.Article.objects.filter(user=user_obj).annotate(month=TruncMonth('create_time')).values('month').annotate(c=Count('nid')).values_list('month','c')
# print(date_list) return render(request, "home_site.html", locals()) def article_detail(request,username,article_id):
user_obj = models.UserInfo.objects.filter(username=username).first()
blog = user_obj.blog
cate_list = models.Category.objects.filter(blog=blog).values('pk').annotate(c=Count('article__title')).values_list(
'title', 'c')
tag_list = models.Tag.objects.filter(blog=blog).values('pk').annotate(count=Count('article')).values_list('title',
'count')
date_list = models.Article.objects.filter(user=user_obj).extra(
select={'y_m_date': "date_format(create_time,'%%Y-%%m')"}).values('y_m_date').annotate(
c=Count('nid')).values_list('y_m_date', 'c') article_obj = models.Article.objects.filter(pk=article_id).first()
comment_list = models.Comment.objects.filter(article_id=article_id)
return render(request, "article_detail.html", locals())
# {'context':context,'blog':blog,'article_obj':article_obj,'comment_list':comment_list} def digg(request):
print(request.POST)
article_id=request.POST.get('article_id')
# is_up=request.POST.get('is_up') # 字符串
is_up=json.loads(request.POST.get('is_up')) # 字符串
# 点赞人即当前登录人
user_id=request.user.pk # 重复点赞和反对--都无效
obj=models.ArticleUpDown.objects.filter(user_id=user_id,article_id=article_id).first()
response={'state':True,'msg':None}
if not obj:
ard=models.ArticleUpDown.objects.create(user_id=user_id,article_id=article_id,is_up=is_up)
queryset= models.Article.objects.filter(pk=article_id)
if is_up:
queryset.update(up_count=F('up_count')+1)
else:
queryset.update(down_count=F('up_count')+1) else:
response['state']=False
response['handled']=obj.is_up
return JsonResponse(response) def comment(request):
"""
提交评论视图函数
功能:
1 保存评论
2 创建事务
3 发送邮件
:param request:
:return:
"""
print(request.POST) article_id = request.POST.get("article_id")
pid = request.POST.get("pid")
content = request.POST.get("content")
user_id = request.user.pk article_obj=models.Article.objects.filter(pk=article_id).first()
# 事务 from django.db import transaction
with transaction.atomic():
comment_obj=models.Comment.objects.create(user_id=user_id,article_id=article_id,content=content,parent_comment_id=pid)
# 数据同步 F比较两个字段
models.Article.objects.filter(pk=article_id).update(comment_count=F('comment_count')+1) response={}
response['create_time']=comment_obj.create_time.strftime("%Y-%m-%d %X")
response['username']=request.user.username
response['content']=content # 发邮件
from django.core.mail import send_mail
from cnblog import settings
import threading
t=threading.Thread(target=send_mail,args=('您的文章%s新增了一条内容' % article_obj.title,content,
settings.EMAIL_HOST_USER,
["836342406@qq.com"]))
t.start() return JsonResponse(response) def get_comment_tree(request):
article_id=request.GET.get('article_id')
ret=list(models.Comment.objects.filter(article_id=article_id).values('pk','content','parent_comment_id'))
return JsonResponse(ret,safe=False)
article_detail.html
{% extends "base.html" %} {% block content %}
{% csrf_token %} <div class="article_info">
<h3 class="text-center title">{{ article_obj.title }}</h3>
<div class="cont">
{{ article_obj.content|safe }}
</div>
{# 博客园的点赞样式 ----#}
<div class="">
<div id="div_digg">
{# 点赞#}
<div class="diggit action">
<span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
</div>
{# 反对#}
<div class="buryit action">
<span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
</div>
<div class="clear"></div>
<hr>
<hr>
<div class="diggword" id="digg_tips" style="color: red;" ></div>
</div> </div>
</div>
{# 点赞#}
<script>
$("#div_digg .action").click(function () {
var is_up = $(this).hasClass("diggit"); $obj = $(this).children("span"); $.ajax({
url: "/digg/",
type: "post",
data: {
"csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
"is_up": is_up,
"article_id": "{{ article_obj.pk }}",
},
success: function (data) {
console.log(data); if (data.state) {
var val = parseInt($obj.text());
$obj.text(val + 1);
}
else {
var val2 = data.handled ? "您已经推荐过!" : "您已经反对过!";
$("#digg_tips").html(val2); setTimeout(function () {
$("#digg_tips").html("")
}, 1000) } }
})
});
{#评论请求#}
$('.comment_btn').click(function () {
var content = $("#comment_content").val();
$.ajax({
url:'/comment/',
type: 'post',
data: { "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
"article_id": "{{ article_obj.pk }}",
"content": content,
pid: pid},
success:function (data) {
console.log(data)
}
})
}) </script> {# 评论#}
<div class="comments list-group">
<p class="tree_btn">评论树</p>
<div class="comment_tree">
{# <div comment_id="'1">#}
{# <span></span>#}
{# </div>#}
{# <div comment_id="'2">#}
{# <span></span>#}
{# </div>#}
{# <div comment_id="'3">#}
{# <span></span>#}
{# </div>#} </div>
{#-------评论树-------#}
<script> $.ajax({
url: "/get_comment_tree/",
type: "get",
data: {
article_id: "{{ article_obj.pk }}"
},
success: function (comment_list) {
console.log(comment_list); $.each(comment_list, function (index, comment_object) { var pk = comment_object.pk;
var content = comment_object.content;
var parent_comment_id = comment_object.parent_comment_id;
var s = '<div class="comment_item" comment_id=' + pk + '><span>' + content + '</span></div>'; if (!parent_comment_id) { $(".comment_tree").append(s);
} else {
$("[comment_id=" + parent_comment_id + "]").append(s);
}
})
}
}) </script> <p>评论列表</p>
<ul class="list-group comment_list">
{% for comment in comment_list %}
<li class="list-group-item">
<div>
<a href=""># {{ forloop.counter }}楼</a>
<span>{{ comment.create_time|date:"Y-m-d H:i" }}</span>
<a href=""><span>{{ comment.user.username }}</span></a>
<a class="pull-right reply_btn" username="{{ comment.user.username }}"
comment_pk="{{ comment.pk }}">回复</a>
</div> {% if comment.parent_comment_id %}
<div class="pid_info well">
<p>
{{ comment.parent_comment.user.username }}: {{ comment.parent_comment.content }}
</p>
</div>
{% endif %}
<div class="comment_con">
<p>{{ comment.content }}</p>
</div>
</li>
{% endfor %}
</ul>
<p>发表评论</p>
<p>昵称:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size=""
value="{{ request.user.username }}">
</p>
<p>评论内容:</p>
<textarea name="" id="comment_content" cols="" rows=""></textarea>
<p>
<button class="btn btn-default comment_btn">提交评论</button>
</p>
</div> <script> var pid='';
$('.comment_btn').click(function () {
{#根评论#}
{#var pid='';#}
var content=$('#comment_content').val(); if(pid){
var index=content.indexOf('\n');
content=content.slice(index+1)
}
$.ajax({
url:'/comment/',
type:'post',
data:{ "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
'article_id':'{{ article_obj.pk }}','content':content ,'pid':pid},
success:function (data) {
console.log(data); var create_time = data.create_time;
var username=data.username;
var content=data.content; // 构建标签字符串 es6语法
var s = `
<li class="list-group-item">
<div> <span>${create_time}</span>
<a href=""><span>${username}</span></a> </div>
<div class="comment_con">
<p>${content}</p>
</div> </li>`; $("ul.comment_list").append(s); // 传回数据后,清空评论框中的内容
$('#comment_content').val('');
pid=''
} })
}); // 回复按钮事件 $('.reply_btn').click(function () {
$('#comment_content').focus();
// 找父评论
var val='@'+$(this).attr('username')+'\n';
$('#comment_content').val(val)
pid=$(this).attr('comment_pk')
}) </script> {% endblock %}
home_site.html
{% extends 'base.html'%}
{% block css %} {% endblock %} {% block content %} {# 文章样式#}
<div class="article_list">
{% for article in article_list %}
<div class="article-item clearfix">
<h5><a href="/{{ article.user.username }}/articles/{{ article.pk }}">{{ article.title }}</a></h5>
<div class="article-desc">
{{ article.desc }}
</div>
<div class="small pub_info pull-right">
<span>发布于 {{ article.create_time|date:"Y-m-d H:i" }}</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 %}
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title> <style>
* {
margin: 0;
padding: 0
} .header {
width: 100%;
height: 60px;
background-color: #
} .header .title {
font-size: 18px;
font-weight: 100;
line-height: 60px;
color: white;
margin-left: 15px
} .backend {
float: right;
margin-right: 15px;
color: white;
text-decoration: none;
} .article_info .title{
margin-bottom: 100px;
} {% block css %} {% endblock %}
</style> <link rel="stylesheet" href="/static/blog/bootstrap-3.3.7/css/bootstrap.css"> {# 在base引入home_site 和 article_datail的样式#}
<link rel="stylesheet" href="/static/css/article_detail.css" >
<link rel="stylesheet" href="/static/css/home_site.css" > <script src="/static/JS/jquery-3.2.1.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="/static/blog/bootstrap-3.3.7/js/bootstrap.min.js"></script> </head>
<body>
<div class="header">
<div class="content">
<p class="title">
<span>{{ blog.title }}</span>
<a href="" class="backend">管理</a>
</p>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-3">
<div class="panel panel-warning">
<div class="panel-heading">我的标签</div>
<div class="panel-body">
{% for tag in tag_list %}
<p><a href="/{{ 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 cate in cate_list %}
<p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p>
{% endfor %}
</div>
</div> <div class="panel panel-success">
<div class="panel-heading">随笔归档</div>
<div class="panel-body">
{% for date in date_list %}
<p><a href="/{{ username }}/archive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p>
{% endfor %}
</div>
</div> </div>
<div class="col-md-9">
{% block content %} {% endblock %}
</div>
</div>
</div> </body>
</html>
BBS-文章详情页、评论、评论树的更多相关文章
- Django:文章详情页面评论功能需要登录后才能使用,登录后自动返回到文章详情页
背景: 文章详情页正在查看文章,想评论一下写的不错,但是需要先登录才能.页面长这个样子: 方案: 1.点击登录链接时,将该页面的URL传递到登录视图中 request.path获取的是当前页面的相对路 ...
- BBS之文章详情页搭建
博客评论相关 博客文章详情页搭建 {% extends 'base.html' %} {% block css %} <style> #div_digg { float: right; m ...
- BBS项目分布搭建三(个人站点时间归档补充,实现侧边栏跳转、无线级分类、实现文章详情页展示功能)
BBS项目分布搭建三(个人站点时间归档补充,) 1. 个人站点时间归档 """ settings.py设置最好更改以下: LANGUAGE_CODE = 'zh-hans ...
- python 全栈开发,Day81(博客系统个人主页,文章详情页)
一.个人主页 随笔分类 需求:查询当前站点每一个分类的名称以及对应的文章数 完成这个需求,就可以展示左侧的分类 它需要利用分组查询,那么必须要会基于双下划线的查询. 基于双下划线的查询,简单来讲,就是 ...
- django博客项目8:文章详情页
首页展示的是所有文章的列表,当用户看到感兴趣的文章时,他点击文章的标题或者继续阅读的按钮,应该跳转到文章的详情页面来阅读文章的详细内容.现在让我们来开发博客的详情页面,有了前面的基础,开发流程都是一样 ...
- HelloDjango 第 08 篇:开发博客文章详情页
作者:HelloGitHub-追梦人物 文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库 首页展示的是所有文章的列表,当用户看到感兴趣的文章时,他点击文章的标题或者继续阅读的按 ...
- 安卓开发——WebView+Recyclerview文章详情页,解决高度问题
安卓开发--WebView+Recyclerview文章详情页,解决高度问题 最近在写一个APP时,需要显示文章详情页,准备使用WebView和RecyclerView实现上面文章,下面评论.出现了W ...
- thinkPHP中的文章详情页实现“上一篇下一篇”功能经验分享
前段时间在公司中接触到了用thinkPHP搭建的项目,其中涉及到了文章详情页上一篇下一篇翻页的功能实现效果. 因为刚接触这套框架和PHP,所以整理一下实现该功能的经验方法. 如果有不到位的地方,欢迎指 ...
- dedecms5.7的文章详情页页面标题加载指定txt文本的随机关键字
dedecms5.7的文章详情页加载指定txt文本的随机关键字 1 实现代码如下 {dede:name runphp='yes'} $file_path = "../test.txt&quo ...
随机推荐
- MySQL数据库InnoDB存储引擎中的锁机制(转载)
http://www.uml.org.cn/sjjm/201205302.asp 00 – 基本概念 当并发事务同时访问一个资源的时候,有可能导致数据不一致.因此需要一种致机制来将访问顺序化. 锁就是 ...
- python面向对象:类空间,对象空间, 组合
一. 类空间,对象空间 1. 类空间,对象空间 创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性 而类有两种属性:静态属性和动态属性 静态属性就是直接在类中定义的变 ...
- [UE4]移动相机,使用Arrow组件来标记移动位置
一.创建一个Arrow组件来标记要移动的位置(Arrow的用法之一就是用来标注坐标). 二.使用TimeLine时间轴结合插值Lerp来移动相机
- Linux在线安装git
一.先检测是否已安装git#rpm -qa | grep zlib-devel 二.提前 安装gcc#yum install gcc 三.具体安装命令 Git下载路径:https://www.kern ...
- U3D学习08-异步、协程
1.调用 invoke不能传参, 2.协程(不是线程,拥有自己独立的执行序列) Coroutine(尽可能减少计算,提高运行效率) 需要迭代器IEnumerate,迭代器中有返回方法yield 协程的 ...
- 我推荐阅读的微信公众号-IT类
微信,正深刻影响着我们的生活,每个使用微信的人,从微信这个窗口去了解这个世界. 微信公众号,微信生态圈是核心功能之一,每天都有大量的文章创作.传播.转发出来,海量的信息扑面而来,微信阅读成为微信使用者 ...
- Mysql-Client编码问题
Mysql编码问题! 首先,安装完mysql之后,登录进去(从控制台), 先要查看mysql编码:SHOW VARIABLES LIKE 'char%': (我这里是修改好的) 如果是没修改的,因为当 ...
- urllib模块学习
一.urllib库 概念:urllib是Python自带的一个用于爬虫的库,其主要作用就是可以通过代码模拟浏览器发送请求.其常被用到的子模块在Python3中的为urllib.request和urll ...
- 针对开发项目的NABCD的分析
N(Need需求) 我们的创意是用户登录我们的软件,就可以实现自己修改图片,添加文字.解决了目前用户不知道如何P图,如何添加文字的难题. A(Approach做法) 我们的团队将用VS软件开发一个修改 ...
- C#提取双引号中的字符串
public static void Main(string[] args) { string strtmp = "123\"456\"qqq\"789\&qu ...