Django 博客

阅读: 评论:0

Django 博客

Django 博客

前言

上一篇Comment模型有一个问题,当我们要获取一篇文章的所以评论时
需要通过parent为空的Comment对象,一级一级的通过commet.children.all()获取
如果层级或者评论很多,需要对每一条评论都查询是否有回复,每一次查询都要对数据库查询,并且数据库查询都是相对很慢的

什么是MPTT

MPTT(Modified Preorder Tree Traversal)是一种在数据库中存储层次结构的技术,它可以让相关操作更加高效

MPTT使得大多数树操作在查询方面更高效。实际上,所有这些操作最多需要一个查询,有时为零:

  • 获取节点的后代
  • 获取节点的祖先
  • 在给定的级别上获取所有节点
  • 获取叶子节点

这个不需要再次查询数据库:

  • 计算给定节点的后代的数量

使用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, rghttree_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')

PostViewget_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标签里,会添加两个上下文变量nodechildren

  • 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小时内删除。

标签:博客   Django
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23