标签:bee 参数 读取 review ida img indent subscript als
目录
在应用下新建一个名字必须叫template_tag文件夹
在该文件夹内新建任意名称的py文件
在py文件内,固定先写下面的两句代码
除了拷贝html代码之外
还需要将配套的css代码也拷贝过来
如果css代码中引用了图片 为了防止图片防盗链 应该下载到本地
点击提交点赞点踩
如何区分用户点赞还是点踩
给点赞点踩标签统一加了一个相同的类名
给该类名绑定点击事件
利用this指点的是当前被操作对象本身再加上判断某个标签是否有某个属性
能够得出用户点的赞还是踩(hasClass())
向后端发送ajax请求
回调函数
展示提示信息
成功
提示
将对于的数字加一
一定要转数值类型再相加
失败
提示
校验当前请求是ajax请求
`request.is_ajax()`
校验当前用户是否登录
`request.user.is_authenticated()`
校验的当前用户是否点的是自己的文章
根据文章id获取文章对象,利用文在哪个对象查询改文章的作者
与当前登录的用户进行比对
request.user == article_obj.blog.userinfo
校验当前用户是否已经给当前文章点过了
只需要去点赞点踩表中查询用户是当前用户并且文章id是前端传来的id
操作数据库
两个地方需要修改
点赞点踩表
文章表中的普通字段
先考虑根评论 再考虑子评论
区分当前用户是否登录
没有登录的情况下,只展示登录注册
鞥路的情况下才展示评论框
给提交的评论按钮绑定点击事件
发送ajax请求
评论内容
文章id
csrf
回调函数
将评论框中内容清空
临时渲染
利用模板字符串
利用DOM操作将临时创建的模板字符串添加到正常的文档流中
刷新渲染
手动添加html代码
子评论
研究点击回复按钮发生的事情
1.将当前想要评论的评论人的姓名
2.将拼接号的内容添加到评论框中
3.评论框自动聚焦
focus()
提交根评论与提交子评论点击的是相同的按钮
根评论与子评论唯一的区别仅仅在于是否有parentid赋值
朝后端发送
后端parentid无论是否传值都不会影响存储
所以你的提交代码写一份就可以
需要避免的问题
提交子评论之后一定要将全局变量名充值为空
在存储数据的时候,要对数据进行切割操作
在渲染评论楼的时候,针对子评论需要多渲染一个根评论人的名字
comment.parent.user.username
获取数据直接操作数据库
也是两个地方需要修改
用了事务
定义文章的后台管理界面
使用导航条
然后使用侧边栏相关(左)
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
<a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
Collapsible Group Item #1
</a>
</h4>
</div>
<div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body">
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
</div>
</div>
</div>
</div>
右侧使用标签栏
<div>
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#home" aria-controls="home" role="tab" data-toggle="tab">Home</a></li>
<li role="presentation"><a href="#profile" aria-controls="profile" role="tab" data-toggle="tab">Profile</a></li>
<li role="presentation"><a href="#messages" aria-controls="messages" role="tab" data-toggle="tab">Messages</a></li>
<li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Settings</a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="home">...</div>
<div role="tabpanel" class="tab-pane" id="profile">...</div>
<div role="tabpanel" class="tab-pane" id="messages">...</div>
<div role="tabpanel" class="tab-pane" id="settings">...</div>
</div>
</div>
在右侧的侧边栏设置模板,用来继承整体显示
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="home">
{% block article %}
文章页面
{% endblock %}
</div>
<div role="tabpanel" class="tab-pane" id="profile">
随笔页面
</div>
<div role="tabpanel" class="tab-pane" id="messages">3</div>
<div role="tabpanel" class="tab-pane" id="settings">4</div>
</div>
文件模板继承
{% extends 'backend/backend_base.html' %}
{#文章页面展示#}
{% block article %}
<table class="table table-striped table-hover">
<thead>
<tr>
<th>标题</th>
<th>发布时间</th>
<th>评论数</th>
<th>点赞数</th>
<th>操作</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for article in article_list %}
<tr>
<td><a href="/{{ request.user.user.username }}/article/{{ article.pk }}">{{ article.title }}</a></td>
<td>{{ article.create_time|date:'Y-m-d' }}</td>
<td>{{ article.comment_num }}</td>
<td>{{ article.up_num }}</td>
<td><a href="#">编辑</a></td>
<td><a href="#">删除</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
使用分页器
class Pagination(object):
def __init__(self,current_page,all_count,per_page_num=2,pager_count=11):
"""
封装分页相关数据
:param current_page: 当前页
:param all_count: 数据库中的数据总条数
:param per_page_num: 每页显示的数据条数
:param pager_count: 最多显示的页码个数
用法:
queryset = model.objects.all()
page_obj = Pagination(current_page,all_count)
page_data = queryset[page_obj.start:page_obj.end]
获取数据用page_data而不再使用原始的queryset
获取前端分页样式用page_obj.page_html
"""
try:
current_page = int(current_page)
except Exception as e:
current_page = 1
if current_page <1:
current_page = 1
self.current_page = current_page
self.all_count = all_count
self.per_page_num = per_page_num
# 总页码
all_pager, tmp = divmod(all_count, per_page_num)
if tmp:
all_pager += 1
self.all_pager = all_pager
self.pager_count = pager_count
self.pager_count_half = int((pager_count - 1) / 2)
@property
def start(self):
return (self.current_page - 1) * self.per_page_num
@property
def end(self):
return self.current_page * self.per_page_num
def page_html(self):
# 如果总页码 < 11个:
if self.all_pager <= self.pager_count:
pager_start = 1
pager_end = self.all_pager + 1
# 总页码 > 11
else:
# 当前页如果<=页面上最多显示11/2个页码
if self.current_page <= self.pager_count_half:
pager_start = 1
pager_end = self.pager_count + 1
# 当前页大于5
else:
# 页码翻到最后
if (self.current_page + self.pager_count_half) > self.all_pager:
pager_end = self.all_pager + 1
pager_start = self.all_pager - self.pager_count + 1
else:
pager_start = self.current_page - self.pager_count_half
pager_end = self.current_page + self.pager_count_half + 1
page_html_list = []
# 添加前面的nav和ul标签
page_html_list.append('''
<nav aria-label='Page navigation>'
<ul class='pagination'>
''')
first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
page_html_list.append(first_page)
if self.current_page <= 1:
prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
else:
prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)
page_html_list.append(prev_page)
for i in range(pager_start, pager_end):
if i == self.current_page:
temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
else:
temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
page_html_list.append(temp)
if self.current_page >= self.all_pager:
next_page = '<li class="disabled"><a href="#">下一页</a></li>'
else:
next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
page_html_list.append(next_page)
last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
page_html_list.append(last_page)
# 尾部添加标签
page_html_list.append('''
</nav>
</ul>
''')
return ''.join(page_html_list)
页面的搭建
编辑器的选用kindeditor编辑器
下载
部署
修改
html添加以下代码
<script charset="utf-8" src="/editor/lang/zh-CN.js"></script>
<script>
KindEditor.ready(function(K) {
window.editor = K.create('#editor_id');
});
</script>
输入框的长宽设置
<script>
KindEditor.ready(function (K) {
window.editor = K.create('#id_comment',{
width: '100%',
height:'450px',
resizeType:0
});
});
</script>
配置编辑器的工具栏,其中”/”表示换行,”|”表示分隔符。
[
'source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste',
'plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright',
'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript',
'superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/',
'formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold',
'italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image', 'multiimage',
'flash', 'media', 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak',
'anchor', 'link', 'unlink', '|', 'about'
]
source | HTML代码 |
---|---|
preview | 预览 |
undo | 后退 |
redo | 前进 |
cut | 剪切 |
copy | 复制 |
paste | 粘贴 |
plainpaste | 粘贴为无格式文本 |
wordpaste | 从Word粘贴 |
selectall | 全选 |
justifyleft | 左对齐 |
justifycenter | 居中 |
justifyright | 右对齐 |
justifyfull | 两端对齐 |
insertorderedlist | 编号 |
insertunorderedlist | 项目符号 |
indent | 增加缩进 |
outdent | 减少缩进 |
subscript | 下标 |
superscript | 上标 |
formatblock | 段落 |
fontname | 字体 |
fontsize | 文字大小 |
forecolor | 文字颜色 |
hilitecolor | 文字背景 |
bold | 粗体 |
italic | 斜体 |
underline | 下划线 |
strikethrough | 删除线 |
removeformat | 删除格式 |
image | 图片 |
flash | Flash |
media | 视音频 |
table | 表格 |
hr | 插入横线 |
emoticons | 插入表情 |
link | 超级链接 |
unlink | 取消超级链接 |
fullscreen | 全屏显示 |
about | 关于 |
打印 | |
code | 插入程序代码 |
map | Google地图 |
baidumap | 百度地图 |
lineheight | 行距 |
clearhtml | 清理HTML代码 |
pagebreak | 插入分页符 |
quickformat | 一键排版 |
insertfile | 插入文件 |
template | 插入模板 |
anchor | 插入锚点 |
开设url地址设置
uploadJson:‘地址‘
csrf验证
上传图片、Flash、视音频、文件时,支持添加别的参数一并传到服务器。
KindEditor.ready(function(K) {
K.create('#id', {
extraFileUploadParams : {
item_id : 1000,
category_id : 1
}
});
});
返回格式(json)
成功时
{
"error":0,
"url":文件路径
}
失败时
{
"error":1,
"message":"错误信息"
}
文章的简介如何获取
包括
)如何从html代码中筛选出纯文本内容
如何从html代码中删除script标签
进行筛选
from bs4 import BeautifulSoup
@login_required
def add_article(request):
tag_list = models.Tag.objects.filter(blog=request.user.blog)
category_list = models.Category.objects.filter(blog=request.user.blog)
# 判断用户输入的文章,并获取
if request.method == 'POST':
title = request.POST.get('title')
content = request.POST.get('content')
tags_list = request.POST.getlist('tags')
category_id = request.POST.get('category')
# 先生成一个模块对象
soup = BeautifulSoup(content,'html.parser')
# soup.text # 获取纯文本
tags = soup.find_all() # 获取所有的标签文本
for tag in tags:
if tag.name == 'script':
tag.decompose() # 删除script标签
# 文章简介,截取文章的前150字符
desc = soup.text[0:150]
# 操作数据库
article_obj = models.Article.objects.create(title=title,content=str(soup),desc=desc,category_id=category_id,blog=request.user.blog)
# 去文章与标签的第三张表中手动录入数据,利用bulk_create
obj_list = []
for tag_id in tags_list:
obj_list.append(models.Article2Tag(article=article_obj,tag_id=tag_id))
models.Article2Tag.objects.bulk_create(obj_list)
# 重定向
return redirect('/backend/')
return render(request,'backend/add_article.html',locals())
{% extends 'backend/backend_base.html' %}
{#文章页面展示#}
{% block article %}
<table class="table table-striped table-hover">
<thead>
<tr>
<th>标题</th>
<th>发布时间</th>
<th>评论数</th>
<th>点赞数</th>
<th>操作</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for article in page_queryset %}
<tr>
<td><a href="/{{ request.user.username }}/article/{{ article.pk }}">{{ article.title }}</a></td>
<td>{{ article.create_time|date:'Y-m-d' }}</td>
<td>{{ article.comment_num }}</td>
<td>{{ article.up_num }}</td>
<td><a href="#">编辑</a></td>
<td><a href="#">删除</a></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="text-right">{{ page_obj.page_html|safe }}</div>
{% endblock %}
add_article.py
{% extends 'backend/backend_base.html' %}
{% block article %}
<h3>添加文章</h3>
<form action="" method="post">
{% csrf_token %}
<p>标题</p>
<p><input type="text" name="title" class="form-control"></p>
<p>内容使用kind编辑器</p>
<p>
<textarea name="content" id="id_comment" cols="30" rows="10" class="form-control"></textarea>
</p>
<p>标签</p>
<p>
{# 渲染标签#}
{% for tag in tag_list %}
<input type="checkbox" name="tags" value="tag.pk"> {{ tag.name }}
{% endfor %}
</p>
<p>分类</p>
<p>
{# 渲染分类#}
{% for category in category_list %}
<input type="radio" name="category" value="category.pk"> {{ category.name }}
{% endfor %}
</p>
<input type="submit" class="btn btn-success">
</form>
{#kindeditor编辑器的部署#}
<script charset="utf-8" src="/static/kindeditor/kindeditor-all-min.js"></script>
<script>
KindEditor.ready(function (K) {
window.editor = K.create('#id_comment',{
width: '100%',
height:'450px',
resizeType:0,
uploadJson:'/upload_img/',
extraFileUploadParams : {
csrfmiddlewaretoken:'{{ csrf_token }}'
}
});
});
</script>
{% endblock %}
set_avatar
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户更改头像</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<h3>原头像:</h3>
<img src="/media/{{ request.user.avatar }}" alt="">
<div class="form-group">
<label for="mdd">新头像
<img src="/static/img/default.jpg" alt="" width="100px" style="margin-left: 10px" id="img">
</label>
{# 将input上传文件的框隐藏#}
<input type="file" name="avatar" id="mdd" style="display: none;">
</div>
<input type="submit" class="btn btn-primary">
</form>
<script>
$('#mdd').on('change',function () {
{#内置对象FileReader,完成文件的读取操作#}
let MyFileReader = new FileReader();
// 获取用户上传的文件对象
let fileObj = $(this)[0].files[0];
// 让文件阅读器读取文件
MyFileReader.readAsDataURL(fileObj); // 异步io操作
// 等待文件io操作读取完成再执行下面的代码
MyFileReader.onload = function () {
// 将读取之后的内容替换到img标签src属性中
$('#img').attr('src',MyFileReader.result)
}
});
</script>
</body>
</html>
from app01.utils.mypage import Pagination
# 后台管理
@login_required
def backend(request):
article_list = models.Article.objects.filter(blog=request.user.blog)
# 分页器的使用
page_obj = Pagination(current_page=request.GET.get('page',1),all_count=article_list.count())
page_queryset = article_list[page_obj.start:page_obj.end]
return render(request,'backend/backend.html',locals())
from bs4 import BeautifulSoup
@login_required
def add_article(request):
tag_list = models.Tag.objects.filter(blog=request.user.blog)
category_list = models.Category.objects.filter(blog=request.user.blog)
# 判断用户输入的文章,并获取
if request.method == 'POST':
title = request.POST.get('title')
content = request.POST.get('content')
tags_list = request.POST.getlist('tags')
category_id = request.POST.get('category')
# 先生成一个模块对象
soup = BeautifulSoup(content,'html.parser')
# soup.text # 获取纯文本
tags = soup.find_all() # 获取所有的标签文本
for tag in tags:
if tag.name == 'script':
tag.decompose() # 删除script标签
# 文章简介,截取文章的前150字符
desc = soup.text[0:150]
# 操作数据库
article_obj = models.Article.objects.create(title=title,content=str(soup),desc=desc,category_id=category_id,blog=request.user.blog)
# 去文章与标签的第三张表中手动录入数据,利用bulk_create
obj_list = []
for tag_id in tags_list:
obj_list.append(models.Article2Tag(article=article_obj,tag_id=tag_id))
models.Article2Tag.objects.bulk_create(obj_list)
# 重定向
return redirect('/backend/')
return render(request,'backend/add_article.html',locals())
import os
from BBS import settings
# 文章内上传文件的函数
def upload_img(request):
back_dic = {'error':0}
if request.method == 'POST':
# print(request.FILES) # 打印键值对
# 获取用户上传的图片,然后保存在本地
file_obj = request.FILES.get('imgFile')
# 手动拼接存储的文件路径
file_path = os.path.join(settings.BASE_DIR,'media','article_img')
if not os.path.isdir(file_path):
os.mkdir(file_path)
# 保存文件
img_path = os.path.join(file_path,file_obj.name)
with open(img_path,'wb') as f:
for l in file_obj:
f.write(l)
# 成功返回0,back_dic
_url = '/media/article_img/%s'%file_obj.name
back_dic['url'] = _url
return JsonResponse(back_dic)
@login_required
def set_avatar(request):
# 展示用户之前的头像,用户上传新的头像
if request.method == 'POST':
file_obj = request.FILES.get('avatar')
# 方式一,不会自动拼接路径
models.Userinfo.objects.filter(pk=request.user.pk).update(avatar=file_obj)
# 方式二
request.user.avatar = file_obj
request.user.save()
return redirect('/home/')
return render(request,'set_avatar.html',locals())
标签:bee 参数 读取 review ida img indent subscript als
原文地址:https://www.cnblogs.com/fwzzz/p/12037139.html