zoukankan      html  css  js  c++  java
  • Django mptt介绍以及使用

    转自:http://qinxuye.me/article/introduction-and-usage-of-django-mptt/

    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的源码。

  • 相关阅读:
    【故障处理】ORA-12162: TNS:net service name is incorrectly specified (转)
    android studio 编程中用到的快捷键
    java时间格式串
    android Error occurred during initialization of VM Could not reserve enough space for object heap Could not create the Java virtual machine.
    linux安装vmware
    x1c 2017 安装mint18的坑——grub2
    x1c2017 8G版 win linux的取舍纠结记录
    python的try finally (还真不简单)
    kafka+docker+python
    json文件不能有注释
  • 原文地址:https://www.cnblogs.com/waniu/p/2682013.html
Copyright © 2011-2022 走看看