上一篇Comment
模型有一个问题,当我们要获取一篇文章的所以评论时
需要通过parent
为空的Comment
对象,一级一级的通过commet.children.all()
获取
如果层级或者评论很多,需要对每一条评论都查询是否有回复,每一次查询都要对数据库查询,并且数据库查询都是相对很慢的
MPTT(Modified Preorder Tree Traversal)
是一种在数据库中存储层次结构的技术,它可以让相关操作更加高效
MPTT
使得大多数树操作在查询方面更高效。实际上,所有这些操作最多需要一个查询,有时为零:
这个不需要再次查询数据库:
为了在评论模型里使用MPTT
,可以使用django-mptt
django-mptt
是一个帮助你在django模型中使用MPTT的应用
安装django-mptt
pip3 install django-mptt
将django-mptt
添加到INSTALLED_APPS
里
INSTALLED_APPS = (# ...'mptt',
)
创建评论模型,需要继承MPTTModel,并且有一个parent
字段
由于继承MPTTModel
,评论模型就有了level
,lft
, rght
和tree_id
字段,这些字段是MPTT
算法所使用的,一般不会用到
from mptt.fields import TreeForeignKey
dels import MPTTModelclass Comments(MPTTModel):user = models.ForeignKey(User)content = models.TextField()parent = models.TreeForeignKey('self', null=True, blank=True, related_name='children',db_index=True)post = models.ForeignKey(Post)created_time = models.DateTimeField(auto_now_add=True)def __str__(self):tclass MPTTMeta:order_insertion_by = ['-created_time']
接着迁移数据库
python manage.py makemigrations
python manage.py migrate
将上篇文章的Comment
模型都替换成Comments
blog/forms.py
里的CommentForm
+dels import Commentsclass CommentForm(ModelForm):class Meta:
- model = Comment
+ model = Commentsfields = ('content', 'parent', 'user', 'post')
PostView
的get_object
方法,不需要再进行过滤了
def get_object(self, queryset=None):...
- postments = postment_set.all().filter(parent=None).order_by('-created_time')
+ postments = postments_set.all()return post
在blog/templates/blog/detail.html
里直接使用recursetree
标签,就能将评论全部显示出来了
{% load mptt_tags %}
<ul>{% recursetree postments %}<li>{{ t }}{% if not node.is_leaf_node %}<ul>{{ children }}</ul>{% endif %}</li>{% endrecursetree %}
</ul>
recursetree
标签里,会添加两个上下文变量node
和children
node
是一个MPTT
模型对象.children
是一个变量,持有node
节点的子节点的HTML
recursetree
标签会遍历所有根节点,再对根节点的子节点进行递归处理
我们无法知道当前遍历的是第几个节点,不能像for
标签那样通过forloop
获取
所以要修改一下recursetree
标签,将遍历的index
添加到上下文里
将recursetree
的源码复制到blog/templatetags/post_tags.py
,并添加我们的修改
from django.utils.safestring import mark_safe
platetags.mptt_tags import cache_tree_children
from anslation import ugettext as _class RecurseTreeNode(template.Node):def __init__(self, template_nodes, queryset_var):plate_nodes = template_nodesself.queryset_var = queryset_vardef _render_node(self, context, node, length=0, index=0):bits = []context.push()for child _children():bits.append(self._render_node(context, child))#将index添加到上下文里,和forloop一样,也提供四种计数方式context['counter'] = index + 1context['counter0'] = indexcontext['revcounter'] = length - indexcontext['revcounter0'] = length - index - 1context['node'] = nodecontext['children'] = mark_safe(''.join(bits))rendered = der(context)context.pop()return rendereddef render(self, context):queryset = self.solve(context)roots = cache_tree_children(queryset)bits = []#通过enumerate,获取当前的indexfor index, node in enumerate(roots):bits.append(self._render_node(context, node, len(roots), roots.index(node)))return ''.join(bits)@register.tag
def recursetree(parser, token):"""Iterates over the nodes in the tree, and renders the contained block for each node.This tag will recursively render children into the template variable {{ children }}.Only one database query is required (children are cached for the whole tree)Usage:<ul>{% recursetree nodes %}<li>{{ node.name }}{% if not node.is_leaf_node %}<ul>{{ children }}</ul>{% endif %}</li>{% endrecursetree %}</ul>"""bits = ts.split()if len(bits) != 2:raise template.TemplateSyntaxError(_('%s tag requires a queryset') % bits[0])queryset_var = template.Variable(bits[1])template_nodes = parser.parse(('endrecursetree',))parser.delete_first_token()return RecurseTreeNode(template_nodes, queryset_var)
这样又可以使用上篇文章创建的blog/comment.html
模板了
<ul class="uk-comment-list">{% recursetree postments %}<li class="uk-margin-small-top">{% include 'blog/comment.html' with comment=node counter=revcounter level=node.level %}{% if not node.is_leaf_node %}<ul class="uk-comment-list uk-margin-small-top" style="padding-left: 4%">{{ children }}</ul>{% endif %}</li>{% endrecursetree %}
</ul>
django-mptt官方文档
本文发布于:2024-02-02 05:45:51,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170682395241752.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |