Django 博客
来源:互联网 发布:数据脱敏是什么意思 编辑:程序博客网 时间:2024/06/12 19:39
评论模型
由于可以回复评论,所以评论是一个层次架构的模型
所以在模型中,评论是自己的外键,可以通过一条评论获取回复的评论
在blog/models.py
中添加Comment
模型
class Comment(models.Model): user = models.ForeignKey(User) content = models.TextField() #parent为该评论的父评论,所以第一个参数为'self',当为空时表示为第一层级的评论 #指定related_name='children',这样可以父评论通过comment.children获取子评论,默认是通过comment.comment_set获取 parent = models.ForeignKey('self', blank=True, null=True, related_name='children', on_delete=models.SET_NULL) post = models.ForeignKey(Post) created_time = models.DateTimeField(auto_now_add=True) def __str__(self): return self.content class Meta: ordering = ['-created_time']
为了在后台能管理Comment
模型,在blog/admin.py
注册
from blog.models import Commentadmin.site.register(Comment)
然后就是迁移数据库了
python manage.py makemigrationspython manage.py migrate
评论视图
评论适合文章关联的,没有单独的视图,是显示在文章下面的,所以我们修改PostView
在blog/views.py
的PostView
里修改get_object
方法
为post
对象,添加一个comments
属性
def get_object(self, queryset=None): post = super(PostView, self).get_object(queryset) #格式化markdown文章等其他操作 #... #由于post是comment的外键,所以可以通过post.comment_set.all()来获取该文章下的所以评论 #同时过滤出parent=None的评论 post.comments = post.comment_set.all().filter(parent=None).order_by('-created_time') return post
评论模板
修改blog/templates/blog/detail.html
在合适的文章结束的地方添加
<ul> {% for c in post.comments %} <li> {{c.content}} <ul> {% for cc in c.children.all %} <li> {{cc.content}} </li> {% endfor %} </ul> </li> {% endfor %}</ul>
这就是最简单的模板了,这里只显示两个层级的评论
接下来美化一下评论,为了复用,将单条评论的模板提取成一个模板文件blog/comment.html
并且接受评论对象comment
,层级level
和楼数counter
这三个参数
评论是按时间降序排序的,最新的评论在最前面,所以counter
传入的是forloop.revcounter
forloop
是for
标签里计数器,而forloop.revcounter
是翻转计数,从迭代对象的长度递减到0
只有层级level
为1时才显示评论的楼数,level=2
时不显示
通过include
标签可以包含其他模板文件
这样我们的模板就变成下面这样了
<ul> {% for c in post.comments %} <li> {% include 'blog/comment.html' with comment=c level=1 counter=forloop.revcounter %} <ul> {% for cc in c.children.all|dictsort:'created_time' %} <li> {% include 'blog/comment.html' with comment=cc level=2 %} </li> {% endfor %} </ul> </li> {% endfor %}</ul>
接下来编写comment.html
我使用的是UIKit3前端框架,所以一条评论的HTML
大概是这样的
<article class="uk-comment"> <header class="uk-comment-header"> <img class="uk-comment-avatar" src="" alt=""> <h4 class="uk-comment-title"></h4> <ul class="uk-comment-meta uk-subnav"></ul> </header> <div class="uk-comment-body"></div></article>
新建blog/templates/blog/comment.html
,将相关变量填入,就成下面这样了
<article class="uk-comment uk-comment-primary uk-visible-toggle"> <header class="uk-comment-header uk-position-relative"> <div class="uk-grid-medium uk-flex-middle" uk-grid> <div class="uk-width-auto"> <img class="uk-comment-avatar" src="https://getuikit.com/docs/images/avatar.jpg" width="80" height="80" alt=""> </div> <div class="uk-width-expand"> <h4 class="uk-comment-title uk-margin-remove"> <a class="uk-link-reset" href="#">{{ comment.user.username }}</a> </h4> <p class="uk-comment-meta uk-margin-remove-top"> <a class="uk-link-reset" href="#">{{ comment.created_time }}</a> </p> </div> </div> {% if level == 1 %} <div class="uk-position-bottom-right uk-position-small"> <span class="uk-link-muted" href="#">#{{ counter }}</span> </div> <div class="uk-position-top-right uk-position-small uk-hidden-hover"> <a class="uk-link-muted" href="#">Reply</a> </div> {% endif %} </header> <div class="uk-comment-body"> <p>{{ comment.content }}</p> </div></article>
现在的页面还不能发表评论,所以只能在后台界面手动添加评论来查看效果了
其中有个回复按键Reply
,下面来实现类似csdn
的评论功能
发表评论
要实现评论功能,可以通过提交表单实现,这里使用了django
的模型表单类ModelForm
新建blog/forms.py
文件,用来放置自定义表单类
自定义一个CommentForm
类,用来表示一个评论表单
from django.forms import ModelFormfrom blog.models import Commentclass CommentForm(ModelForm): class Meta: model = Comment fields = ('content', 'parent', 'user', 'post')
有了表单类,就需要想办法吧表单对象传递给模板
只需要在blog/views.py
对PostView
覆写get_context_data
方法
这个方法在get
方法里调用,用来生成上下文传递给模板
因此直接创建一个CommentForm
,添加到上下文里
from blog.forms import CommentForm...def get_context_data(self, **kwargs): context = super(PostView, self).get_context_data(**kwargs) form = CommentForm() context.update({'form': form}) return context
有了表单对象之后,就可以在模板里使用了,注意name
属性要和CommentForm
的fields
对应上
这样提交的时候,表单和表单对象才可以对应上
同时必须有{% csrf_token %}
标签,防止csrf
攻击
<form method="post"> {% csrf_token %} <textarea name="{{ form.content.name }}" id="replay_comment_content" required></textarea> <input type="hidden" name="{{ form.parent.name }}" id="replay_comment_id"> <input type="hidden" name="{{ form.user.name }}" value="{{ user.id }}"> <input type="hidden" name="{{ form.post.name }}" value="{{ post.id }}"> <button>submit</button></form>
form.content
是评论内容,需要用户填写的 form.parent
是被回复的评论的评论对象 form.user
是当前登录的用户 form.post
是当前的文章
后面三个是对用户不可见的,form.parent
的值是当用户点击回复按键才会填充的,可以为空,而form.user
和form.post
的值是一打开页面就确定了
观察csdn
的回复评论的流程,可以发现,当随意点击其中一个回复按键,就会跳转到评论框,并且会在评论框填充[reply]被回复的用户名[/reply]
跳转到评论框可以通过设置锚点,而评论框填充内容就需要javascript
来实现了
首先修改blog/templates/blog/comment.html
,在回复按键上添加class="reply_button"
,方便在js
获取所有回复按键
将href="#reply"
,点击回复按键时会滚动到id
为reply
的组件上
设置data-id
为评论的id
,data-username
为评论的用户名,用于提交的时候获取被评论的id
和用户名
{% if level == 1 %}- <div class="uk-position-top-right uk-position-small uk-hidden-hover"><a class="uk-link-muted" href="#">Reply</a></div>+ <div class="uk-position-top-right uk-position-small uk-hidden-hover"><a class="uk-link-muted reply_button"+ href="#reply"+ data-id="{{ comment.id }}"+ data-username="{{ comment.user }}">Reply</a>+ </div>{% endif %}
再将表单的id
设置为reply
,onsubmit
设置为return onSubmitComment()
,用于在提交的时候做一些处理
<form method="post" onsubmit="return onSubmitComment()" id='reply'> ...</form>
接下来编写javascript
代码,因为代码会使用到jquery
,所以必须写在引入jquery
文件的后面
在blog/templates/blog/base.html
里所以js
文件导入后面添加一个block afterbody
<script src="https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.30/js/uikit.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.30/js/uikit-icons.min.js"></script>+{% block afterbody %}{% endblock %} </body> </html>
在blog/templates/blog/detail.html
里添加如下代码
{% block afterbody %} <script> $('#reply_button').click(function () { $('#replay_comment_id').val($(this).data('id')); $('#replay_comment_content').val('[reply]'+$(this).data('username')+'[/reply]\n'); }); function onSubmitComment() { var content = $('#replay_comment_content').val(); var newstr = content.replace(/^\[reply\].*?\[\/reply\]\n/, ''); if (newstr) { if (newstr === content) { $('#replay_comment_id').val(''); } $('#replay_comment_content').val(newstr); return true; } return false; } </script>{% endblock %}
通过$('#reply_button').click()
为所有回复按键添加点击事件
当点击回复按键时将表单的parent
组件(id
为replay_comment_id
)设置为$(this).data('id')
,也就是对应刚刚设置的data-id
属性
将表单的content
组件(id
为replay_comment_content
)设置为'[reply]'+$(this).data('username')+'[/reply]\n'
,提示回复的是哪个用户
当点击提交按键时,调用onSubmitComment
函数,这里会取出提交的评论内容,去掉我们添加的[reply]用户名[/reply]
如果没有我们添加的内容,说明是直接发表评论,也可能是用户自己删掉提示内容,这时候需要将parent
字段置空
到这里前端的内容都搞完了,由于提交时一个POST
请求,还需要后端处理
又回到PostView
,添加一个def post(self, request, *args, **kwargs)
方法,POST
请求会调用post
方法
用request.POST
构建一个CommentForm
,request.POST
包含了所有表单参数
当CommentForm
有效时直接调用save
方法保存到数据库里面,最后通过redirect
重定向会我们的文章页面,避免重复提交表单
from django.shortcuts import render, redirect... def post(self, request, *args, **kwargs): obj = self.get_object() form = CommentForm(request.POST) if form.is_valid(): form.save() return redirect(obj)
当然,后端也应该验证传入的参数,判断用户权限等,这里就先省略了
- Django 博客
- Django 博客
- Django 博客
- Django 博客
- Django 博客
- Django 博客
- Django 博客
- Django 博客
- Django 博客
- Django 博客
- Django--博客
- django搭建简易博客
- django创建博客
- django 博客一
- django博客二
- django博客三
- django博客四
- Zinnia - Django 博客框架
- 动态代理机制
- ThreadPoolExecutor线程池源码分析
- Java 加密解密zip文件(亲测有效,附源码和jar包)
- PHP-BOM
- Ubuntu 17.10 将“关闭、最小化、最大化”按钮移动到标题栏左侧
- Django 博客
- tomcat 单点登录 SSO 原理分析
- 移动端证件识别采用视频预览模式识别
- Android studio 错误 (10048)的错误:解决通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
- TOP100summit2017:网易测试总监钱蓓蕾——新时代测试正走向精英化、自动化、智能化
- WEEK4 JAVA 作业
- JavaScript 实现全选,分组全选,列表折叠。
- Smoke Test & Daily Build
- 单链表