Django mptt介绍以及使用

Django mptt是个Django第三方组件,目标是使Django项目能在数据库中存储层级数据(树形数据)。它主要实现了修改过的前序遍历算法,如果你对原理还不是很了解,可以看我的这篇文章。当然,使用mptt时,原理是可以不用了解的,因为具体的实现细节都已经隐藏。不过,如果项目不是使用的Django,可以参考具体的实现原理。

在整篇文章中,我们将会拿《在数据库中存储层级结构》中的例子作为本文的例子。我们打算在数据库中存储这张图中的数据:

树

在介绍mptt之前,如果你的需求仅仅是像这样显示以上数据:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
< 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。

?
1
2
3
4
5
6
7
8
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 ):
         return self .title

开启自动admin,在后台添加完数据。接着,我们来看看怎么样使用unordered_list这个过滤器来显示树形图。

按照官方文档的说法,显示时传递给template的数据应该是这样:

?
1
[ 'Food' , [ 'Fruit' , [ 'Red' , [ 'Cherry' ], 'Yellow' , [ 'Banana' ]], 'Meat' , [ 'Beef' , 'Pork' ]]]

我们需要写一个递归的工具函数:

?
1
2
3
4
5
6
7
8
9
10
11
def display(foods):
     display_list = []
 
     for food in foods:
         display_list.append(food.title)
 
         children = food.children. all ()
         if len (children) > 0 :
             display_list.append(display(food.children. all ()))
         
     return display_list

于是在views中,我们只要得到根节点,然后把disaply函数生成的列表传递给template,就像这样:

?
1
2
3
4
5
6
7
from django.shortcuts import render_to_response
 
def unordered_list(request):
     foods = Food.objects. filter (parent = None )
     var = display(foods)
     
     return render_to_response( 'mpttexample/unordered_list.html' , { 'var' : var})

最后在模板中添加:

?
1
{{ var|unordered_list }}

就可以看到显示效果了。

关于unordered_list过滤器的用法就介绍到这里。因为有时候需求不止这么简单,比如有时需要展现样式等等,unordered_list就远远不够了。这个时候就需要mptt,下面开始介绍mptt的用法。

首先是安装mptt,如果安装了setup tools,就可以用这个指令:

easy_install django-mptt

下载包安装的方式就不赘述了,下载地址在这里

安装完成后,需要在settings文件下的INSTALLED_APPS中添加'mptt'。

接着写Models,这里我们的Models相之前的实现几乎没有任何的变化。只需继承MPTTModel类:

?
1
2
3
4
5
6
class MPTTFood(MPTTModel):
     title = models.CharField(max_length = 50 )
     parent = models.ForeignKey( "self" , blank = True , null = True , related_name = "children" )
     
     def __unicode__( self ):
         return self .title

这里需要说明的是,实际上MPTTModel隐藏了四个变量:level,lft,rght和tree_id。大多数时候我们是用不到这几个变量的。另外,如果你的Model中parent变量名字不是"parent"时,应当在Model类中MPTT元类中指明:

?
1
2
3
4
5
6
7
8
9
10
11
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" )
     
     class MPTTMeta:
         parent_attr = 'parent_food'
 
     def __unicode__( self ):
         return self .title

Model的其他选项,请参考官方说明

对于继承MPTTModel的类的实例,将会有额外的方法,比如get_ancestors(更多参考文档)。我们运行manage.py shell命令作实验:

python manage.py shell

mptt shell

如果安装了自动Admin,可以在Admin模板中像这样显示数据:

mptt admin

只需在admin.site注册,像这样:

?
1
2
3
4
from django.contrib import admin
from mptt.admin import MPTTModelAdmin
 
admin.site.register(MPTTFood, MPTTModelAdmin)

接下来的话题,就是怎样在模板中显示的问题。我们来修改之前ordered_list的显示,结构是一样的,只是对于叶子节点,我们让它显示成红色。在模板中,不要忘了加”{% load mptt_tags %}“。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
{% load mptt_tags %}
{% recursetree nodes %}
< li >
     {% if node.is_leaf_node %}
     < span style = "color: red;" >{{ node.title }}</ span >
     {% else %}
         {{ node.title }}
         < ul >
             {{ children }}
         </ ul >
     {% endif %}
</ li >
{% endrecursetree %}

这里在视图中传递给模板的参数名必须是nodes。views中就像这样:

?
1
2
3
4
def mptt(request):
     nodes = MPTTFood.tree. all ()
     
     return render_to_response( 'mpttexample/mptt.html' , { 'nodes' : nodes})

模板中的其他用法,请参考官方文档

关于mptt的介绍就到这里,如果以上这些不能满足你的需求,如在django forms中使用mptt form field等等,请继续参考MPTT官方文档。

过段时间,再和大家分享MPTT的源码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值