Django 树形结构实现方法

发表于:2017-8-08 10:14

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:未知    来源:csdn

  Django mptt介绍以及使用
  Django mptt是个Django第三方组件,目标是使Django项目能在数据库中存储层级数据(树形数据)。它主要实现了修改过的前序遍历算法,如果你对原理还不是很了解,可以看我的这篇文章。当然,使用mptt时,原理是可以不用了解的,因为具体的实现细节都已经隐藏。不过,如果项目不是使用的Django,可以参考具体的实现原理。
  在整篇文章中,我们将会拿《在数据库中存储层级结构》中的例子作为本文的例子。我们打算在数据库中存储这张图中的数据:
  在介绍mptt之前,如果你的需求仅仅是像这样显示以上数据:
  <li>Food 
  <ul> 
  <li>Fruit 
  <ul> 
  <li>Red 
  <ul> 
  <li>Cherry</li> 
  </ul> 
  </li> 
  <li>Yellow 
  <ul> 
  <li>Banana</li> 
  </ul> 
  </li> 
  </ul> 
  </li> 
  <li>Meat 
  <ul> 
  <li>Beef</li> 
  <li>Pork</li> 
  </ul> 
  </li> 
  </ul> 
  </li>
  mptt就显得大材小用了,因为Django已经有内置模板过滤器来完成这个工作:unordered_list(官方文档)。如果你的需求不只这么简单,那就跳过这一段。不过这里还是要讲解一下unordered_list的做法。我们就来实现以上的结果。
  当然我们首先要写一个简单的Model。
  from django.db import models 
  class Food(models.Model): 
  title= models.CharField(max_length=50) 
  parent= models.ForeignKey("self", blank=True, null=True, related_name="children") 
  def__unicode__(self): 
  returnself.title
  开启自动admin,在后台添加完数据。接着,我们来看看怎么样使用unordered_list这个过滤器来显示树形图。
  按照官方文档的说法,显示时传递给template的数据应该是这样:
  ['Food', ['Fruit', ['Red', ['Cherry'],'Yellow', ['Banana']],'Meat', ['Beef','Pork']]]
  我们需要写一个递归的工具函数:
  def display(foods): 
  display_list= [] 
  forfood in foods: 
  display_list.append(food.title) 
  children= food.children.all() 
  iflen(children) > 0: 
  display_list.append(display(food.children.all())) 
  returndisplay_list
  于是在views中,我们只要得到根节点,然后把disaply函数生成的列表传递给template,就像这样:
  from django.shortcuts import render_to_response 
  def unordered_list(request): 
  foods= Food.objects.filter(parent=None) 
  var= display(foods) 
  returnrender_to_response('mpttexample/unordered_list.html', {'var': var})
  最后在模板中添加:
  {{ var|unordered_list }}
  就可以看到显示效果了。
  关于unordered_list过滤器的用法就介绍到这里。因为有时候需求不止这么简单,比如有时需要展现样式等等,unordered_list就远远不够了。这个时候就需要mptt,下面开始介绍mptt的用法。
  首先是安装mptt,如果安装了setup tools,就可以用这个指令:
  easy_install django-mptt
  下载包安装的方式就不赘述了,下载地址在这里。
  安装完成后,需要在settings文件下的INSTALLED_APPS中添加'mptt'。
  接着写Models,这里我们的Models相之前的实现几乎没有任何的变化。只需继承MPTTModel类:
  <div class="line number1 index0 alt2"><code class="python keyword">from</code> <code class="python plain">mptt.models </code><code class="python keyword">import</code> <code class="python plain">MPTTModel</code></div> 
  class MPTTFood(MPTTModel): 
  title= models.CharField(max_length=50) 
  parent= models.ForeignKey("self", blank=True, null=True, related_name="children") 
  def__unicode__(self): 
  returnself.title 
  这里需要说明的是,实际上MPTTModel隐藏了四个变量:level,lft,rght和tree_id。大多数时候我们是用不到这几个变量的。另外,如果你的Model中parent变量名字不是"parent"时,应当在Model类中MPTT元类中指明:
  from mptt.models import MPTTModel 
  class MPTTFood(MPTTModel): 
  title= models.CharField(max_length=50) 
  parent_food= models.ForeignKey("self", blank=True, null=True, related_name="children") 
  classMPTTMeta: 
  parent_attr= 'parent_food' 
  def__unicode__(self): 
  returnself.title 
  Model的其他选项,请参考官方说明。
  对于继承MPTTModel的类的实例,将会有额外的方法,比如get_ancestors(更多参考文档)。我们运行manage.py shell命令作实验:
  Python manage.py shell
  如果安装了自动Admin,可以在Admin模板中像这样显示数据:
  只需在admin.site注册,像这样:
  from django.contrib import admin 
  from mptt.admin import MPTTModelAdmin 
  admin.site.register(MPTTFood, MPTTModelAdmin)
  接下来的话题,就是怎样在模板中显示的问题。我们来修改之前ordered_list的显示,结构是一样的,只是对于叶子节点,我们让它显示成红色。在模板中,不要忘了加”{% load mptt_tags %}“。
  {% load mptt_tags %} 
  {% recursetree nodes %} 
  <li> 
  {% if node.is_leaf_node %} 
  <spanstyle="color: red;">{{ node.title }}</span> 
  {% else %} 
  {{ node.title }} 
  <ul> 
  {{ children }} 
  </ul> 
  {% endif %} 
  </li> 
  {% endrecursetree %}
  这里在视图中传递给模板的参数名必须是nodes。views中就像这样:
  def mptt(request): 
  nodes= MPTTFood.tree.all() 
  returnrender_to_response('mpttexample/mptt.html', {'nodes': nodes})
  模板中的其他用法,请参考官方文档。
  关于mptt的介绍就到这里,如果以上这些不能满足你的需求,如在django forms中使用mptt form field等等,请继续参考MPTT官方文档。
  过段时间,再和大家分享MPTT的源码。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号