zoukankan      html  css  js  c++  java
  • 用Django ORM实现树状结构

    前言

    之前看对于用关系数据库实现树状结构的方法就知道一直做自关联的表,但是感觉自关联查询太慢了,最近看到一篇文章,感觉视野开拓了好多,文章:数据库表设计,没有最好只有最适合来自:微信

    下面就针对这里面说的第四种数据结构来实现以下这种树状结构。这样的结构就是牺牲了空间来换取时间,主要就是在查询和删除上快了好多。

    环境介绍

    IDE我用的pycharm

    Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13) 
    [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
    Django 1.11
    
    

    创建Django project和配置app

    从pycharm里面创建Django的project这里面就不多做介绍了,并且创建一个app01
    的app,然后目录结构如下:

    bogon:django18 hongzhi.wang$ tree .
    .
    ├── app01
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── models.py
    │   ├── tests.py
    │   └── views.py
    ├── django18
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── locale
    ├── manage.py
    
    

    创建表结构,重写save方法

    app01的models.py文件如下:

    from django.db import models
    
    # Create your models here.
    
    
    class MysqlRelation(models.Model):
        parent = models.ForeignKey("Mysql", related_name="mysql_parent")
        child = models.ForeignKey("Mysql", related_name="mysql_child")
        depth = models.IntegerField(default=0)
    
        def __str__(self):
            return "%s___%s" % (self.parent, self.child)
    
    
    class Mysql(models.Model):
        name = models.CharField(max_length=30)
        is_slave = models.BooleanField(default=False)
        master = models.ForeignKey("Mysql", null=True, blank=True)
        comment = models.CharField(max_length=100, null=True, blank=True)
    
        def save(self, *args, **kwargs):
            super(Mysql, self).save(*args, **kwargs)  # Call the "real" save() method.
            if self.master:
                MysqlRelation.objects.create(
                    parent=self, child=self, depth=0
                ).save()
                for obj in self.master.mysql_child.all():
                    MysqlRelation.objects.create(
                        parent=obj.parent, child=self, depth=obj.depth+1
                    ).save()
    
        def __str__(self):
            return self.name
    
    

    然后python3 manage.py makemigrations; python3 manage.py migrate本文使用的mysql作为例子,因为mysql的主从关系有时候会形成这种树状结构,(其实如果要用这样的结构还需要重写delete方法,因为django默认的就是那种自关联表的删除,这里就先不实现呢,留到以后吧),如果我要实现

    
    mojideMacBook-Pro-2:tmp hongzhi.wang$ tree v1/
    v1/
    ├── v1-1
    │   └── v1-1-1
    └── v1-2
    

    这样的结构,我的relation表就是这样的:

    parent child depth
    v1 v1 0
    v1 v1-1 1
    v1-1 v1-1 0
    v1 v1-2 1
    v1-2 v1-2 0
    v1 v1-1-1 2
    v1-1 v1-1-1 1
    v1-1-1 v1-1-1 0

    使用django admin创建这样的结构

    app01admin.py文件如下:

    from django.contrib import admin
    
    # Register your models here.
    
    
    from .models import Mysql, MysqlRelation
    
    admin.site.register(Mysql)
    admin.site.register(MysqlRelation)
    
    

    使用django admin创建一个树状的关系结构,到这时models的工作已经做好了,下面我们准备用bootstrap-treeview这个前端插件来展示这个树状结构,本文只是以一个root的树为例讲解,多root的以后再说了。

    创建html文件

    templates下的home.html文件如下:

    <!DOCTYPE html>
    <html lang="en">
    <link href="https://magicbox.bkclouds.cc/static_api/v3/assets/bootstrap-3.3.4/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://magicbox.bkclouds.cc/static_api/v3/assets/js/jquery-1.10.2.min.js"></script>
    <script src="https://magicbox.bkclouds.cc/static_api/v3/assets/bootstrap-3.3.4/js/bootstrap-treeview.js"></script>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="plugin12_demo1" class="treeview"></div>
    <script type="text/javascript">
        // 默认状态
          var defaultData = [{
              text: 'Parent 1',
              nodes: [{
                  text: 'Child 1',
                  nodes: [{
                      text: 'Grandchild 1',
                      nodes :[]
                    },{
                      text: 'Grandchild 2',
                    }]
                },{
                  text: 'Child 2',
                }]
            },{
              text: 'Parent 2',
            }
          ];
        $.getJSON("/data", function (data) {
              $('#plugin12_demo1').treeview({
                data: data
              });
            }
        );
    </script>
    </body>
    </html>
    

    本文直接用的magicbox的static文件,做例子就图省事了,上面的处理AJAX返回的data可以换成defaultData,来看看这个插件的效果。

    urls与views配置

    urls.py如下:

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^$', views.home), # 返回主页面
        url(r'^data', views.data), #返回树状结构的json字符串
    ]
    
    

    app01下views.py如下:

    from django.shortcuts import render
    from . import models
    
    from django.http import JsonResponse
    # Create your views here.
    
    
    def home(request):
        return render(request, 'home.html')
    
    
    def gen_tree(root):
        res = []
        branches = models.Mysql.objects.filter(master=root)
        if branches:
            for branch in branches:
                item = dict(
                            text=branch.name,
                        )
                if models.Mysql.objects.filter(master=branch):
                    item["nodes"] = gen_tree(branch)
                res.append(item)
            return res
    
    
    def data(request):
        '''
        
        :param request: 
        :return: 
         [{
              text: 'Parent 1',
              nodes:[{
                  text: 'child 1',
                  nodes:{}
              },{
                  text: 'child 2',
                  nodes:{}
              }
              ]
          }]
        '''
        res = []
        tree_root = models.Mysql.objects.filter(master__isnull=True).first()
        res.append(dict(text=tree_root.name, nodes=gen_tree(tree_root)))
        return JsonResponse(res, safe=False)
    
    

    到现在为止的目录结构:

    bogon:django18 hongzhi.wang$ tree .
    .
    ├── app01
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── migrations
    │   │   ├── 0001_initial.py
    │   │   ├── __init__.py
    │   ├── apps.py
    │   ├── models.py
    │   ├── tests.py
    │   └── views.py
    ├── db.sqlite3
    ├── django18
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── manage.py
    └── templates
        ├── home.html
    
    

    然后就可以启动django来看看效果了,也可以通过从django admin添加一个节点,然后刷新页面再看看效果。

  • 相关阅读:
    [PHP] class_exists类不存在时会调用__autoload函数
    [Redis] Redis的消息机制- 发布订阅
    [发电] 现在正式入驻爱发电平台
    [MySQL] PHP IP登录限制的实现
    [Redis] 哈希表的Rehash机制
    [Redis] redis的hash类型底层结构哈希表
    [Linux] ls命令的几个常用参数实现按时间/文件大小排序
    [Go] 在gin框架gorm下查询一对多的数据
    [Redis] list底层的数据结构
    [GO]go redis实现滑动窗口限流-redis版
  • 原文地址:https://www.cnblogs.com/WisWang/p/7297755.html
Copyright © 2011-2022 走看看