django项目--菜单管理

后台菜单管理功能

一、业务功能分析

1. 业务需求分析

后台首页菜单根据用户权限动态生成,不同菜单对应不同的功能视图。菜单的增删改查。

2.功能分析

  • 菜单列表
  • 添加菜单
  • 修改菜单
  • 删除菜单

3.模型设计

  1. 字段分析
    • name
    • url
    • parent
    • order
    • permission
    • icon
    • codename
    • is_visible
  2. 模型定义
# 在myadmin/models.py中定义如下模型
from django.db import models
from django.contrib.auth.models import Permission

from utils.models import BaseModel
# Create your models here.


class Menu(BaseModel):
    name = models.CharField('菜单名', max_length=48, help_text='菜单名')
    url = models.CharField('url', max_length=256, null=True, blank=True, help_text='url')
    parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
    order = models.SmallIntegerField('排序', default=0)
    permission = models.OneToOneField(Permission, on_delete=models.SET_NULL, null=True)
    icon = models.CharField('图标', max_length=48, default='fa-link')
    codename = models.CharField('权限码', max_length=48, help_text='权限码', unique=True)
    is_visible = models.BooleanField('是否可见', default=False)

    class Meta:
        ordering = ['-order']
        db_table = 'tb_menu'
        verbose_name = '菜单'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

二、菜单列表

1.业务流程分析

  1. 获取未删除,的一级菜单
  2. 根据一级菜单获取未删除的二级菜单
  3. 渲染页面

2.接口设计

  1. 接口说明
类目 说明
请求方法 GET
url定义 /admin/menus/
参数格式 无参数
  1. 返回结果

    html

3.后端代码

  1. 视图
#  myadmin/views.py下定义如下视图:
class MenuListView(View):
    """
    菜单列表视图
    url:/admin/menus/
    """

    def get(self, request):
        menus = models.Menu.objects.only('name', 'url', 'icon', 'is_visible', 'order', 'codename').filter(is_delete=False, parent=None)

        return render(request, 'myadmin/menu/menu_list.html', context={'menus': menus})

2 . 路由

# admin/urls.py中添加如下路由
path('menus/', views.MenusView.as_view(), name='menu_list'),

4.前端代码

1.html

<!-- 创建templates/myadmin/menu/menu_list.html-->
{% extends 'myadmin/base/content_base.html' %}
{% load static %}
{% block page_header %}系统设置{% endblock %}
{% block page_option %}菜单管理{% endblock %}
{% block content %}
    <div class="box">
        <div class="box-header with-border">
            <h3 class="box-title">菜单列表</h3>
            <div class="box-tools">
                <button type="button" class="btn btn-primary btn-sm">添加菜单
                </button>
            </div>
        </div>
        <!-- /.box-header -->

        <div class="box-body">
            <table class="table table-bordered">
                <tbody>
                <tr>
                    <th>菜单</th>
                    <th>子菜单</th>
                    <th>url</th>
                    <th>图标</th>
                    <th>权限码</th>
                    <th>顺序</th>
                    <th>是否可见</th>
                    <th>逻辑删除</th>
                    <th>操作</th>
                </tr>
                {% for menu in menus %}
                    <tr>

                        <td>{{ menu.name }}</td>
                        <td></td>
                        <td>{{ menu.url|default:'' }}</td>
                        <td>{{ menu.icon }}</td>
                        <td>{{ menu.codename }}</td>
                        <td>{{ menu.order }}</td>
                        <td>{% if menu.is_visible %}是{% else %}否{% endif %}</td>
                        <td style="width: 100px" data-id="{{ menu.id }}" data-name="{{ menu.name }}">
                            {% if menu.children.all %}
                                <button type="button" class="btn btn-info btn-xs edit">编辑</button>
                            {% else %}
                                <button type="button" class="btn btn-info btn-xs edit">编辑</button>
                                <button type="button" class="btn btn-danger btn-xs delete">删除</button>
                            {% endif %}
                        </td>
                    </tr>
                    {% if menu.children.all %}
                        {% for child in menu.children.all %}
                            <tr>
                                <td></td>
                                <td>{{ child.name }}</td>
                                <td>{{ child.url }}</td>
                                <td>{{ child.icon }}</td>
                                <td>{{ child.codename }}</td>
                                <td>{{ child.order }}</td>
                                <td style="width: 80px">{% if child.is_visible %}是{% else %}否{% endif %}</td>
                                <td style="width: 100px" data-id="{{ child.id }}" data-name="{{ child.name }}">
                                    <button type="button" class="btn btn-info btn-xs edit">编辑</button>
                                    <button type="button" class="btn btn-danger btn-xs delete">删除</button>
                                </td>
                            </tr>
                        {% endfor %}
                    {% endif %}

                {% endfor %}

                </tbody>
            </table>
        </div>

    </div>
{% endblock %}

三、添加菜单页面

1. 接口设计

  1. 接口说明:
类目 说明
请求方法 GET
url定义 /admin/menu/
参数格式 无参数
  1. 返回数据

    html

2. 后端代码

  1. 视图

    # 在myadmin/views.py中添加如下视图
    class MenuAddView(View):
        """
        添加菜单视图
        url:/admin/menu/
        """
    
        def get(self, request):
    
            form = MenuModelForm()
            return render(request, 'myadmin/menu/add_menu.html', context={'form': form})
    
  2. 路由

    # 在myadmin/urls.py中添加如下路由
    path('menu/', views.MenuAddView.as_view(), name='add_menu')
    
  3. 表单

    # 在myadmin/forms.py中定义如下表单
    from django import forms
    
    from .models import Menu
    
    
    class MenuModelForm(forms.ModelForm):
        parent = forms.ModelChoiceField(queryset=None, required=False, help_text='父菜单')
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.fields['parent'].queryset = Menu.objects.filter(is_delete=False, is_visible=True, parent=None)
            # https://docs.djangoproject.com/en/2.2/ref/forms/fields/#fields-which-handle-relationships
    
        class Meta:
            model = Menu
            fields = ['name', 'url', 'order', 'parent', 'icon', 'codename', 'is_visible']
    

    为了在渲染表单是能加入自定义css样式,在应用admin中定义自定义标签,在admin下创建templatetags包,在其中创建admin_customer_tags.py模块

    # myadmin/tamplatetags/admin_customer_tags.py
    from django.template import Library
    
    register = Library()
    
    
    @register.simple_tag()
    def add_class(field, class_str):
        return field.as_widget(attrs={'class': class_str})
    
    
#### 3.前端代码

1. html

   ```html
   <!-- 修改 templates/myadmin/menu/menu_list.html -->
   {% extends 'myadmin/base/content_base.html' %}
   {% load static %}
   {% block page_header %}系统设置{% endblock %}
   {% block page_option %}菜单管理{% endblock %}
   {% block content %}
       <div class="box">
           <div class="box-header with-border">
               <h3 class="box-title">菜单列表</h3>
               <div class="box-tools">
                   <button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#modal-add"
                           href="{% url 'admin:add_menu' %}">添加菜单
                   </button>
               </div>
           </div>
           <!-- /.box-header -->
   
           <div class="box-body">
               <table class="table table-bordered">
                   <tbody>
                   <tr>
                       <th>菜单</th>
                       <th>子菜单</th>
                       <th>url</th>
                       <th>图标</th>
                       <th>权限码</th>
                       <th>顺序</th>
                       <th>是否可见</th>
                       <th>操作</th>
                   </tr>
                   {% for menu in menus %}
                       <tr>
   
                           <td>{{ menu.name }}</td>
                           <td></td>
                           <td>{{ menu.url|default:'' }}</td>
                           <td>{{ menu.icon }}</td>
                           <td>{{ menu.codename }}</td>
                           <td>{{ menu.order }}</td>
                           <td>{% if menu.is_visible %}是{% else %}否{% endif %}</td>
                           <td style="width: 100px" data-id="{{ menu.id }}" data-name="{{ menu.name }}">
                               {% if menu.children.all %}
                                   <button type="button" class="btn btn-info btn-xs edit">编辑</button>
                               {% else %}
                                   <button type="button" class="btn btn-info btn-xs edit">编辑</button>
                                   <button type="button" class="btn btn-danger btn-xs delete">删除</button>
                               {% endif %}
                           </td>
                       </tr>
                       {% if menu.children.all %}
                           {% for child in menu.children.all %}
                               <tr>
                                   <td></td>
                                   <td>{{ child.name }}</td>
                                   <td>{{ child.url }}</td>
                                   <td>{{ child.icon }}</td>
                                   <td>{{ child.codename }}</td>
                                   <td>{{ child.order }}</td>
                                   <td style="width: 80px">{% if child.is_visible %}是{% else %}否{% endif %}</td>
                                   <td style="width: 100px" data-id="{{ child.id }}" data-name="{{ child.name }}">
                                       <button type="button" class="btn btn-info btn-xs edit">编辑</button>
                                       <button type="button" class="btn btn-danger btn-xs delete">删除</button>
                                   </td>
                               </tr>
                           {% endfor %}
                       {% endif %}
   
                   {% endfor %}
   
                   </tbody>
               </table>
           </div>
   
       </div>
   
       <!-- add modle -->
       <div class="modal fade" id="modal-add" role="dialog" >
           <div class="modal-dialog">
               <div class="modal-content">
   
               </div>
               <!-- /.modal-content -->
           </div>
           <!-- /.modal-dialog -->
       </div>
       <!-- /.modal -->
   
   {% endblock %}
   <!-- 新建 templates/myadmin/menu/add_menu.html -->
   {% load admin_customer_tags %}
   {% load static %}
   <div class="modal-header">
       <button type="button" class="close" data-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">&times;</span></button>
       <h4 class="modal-title">添加菜单</h4>
   </div>
   <div class="modal-body">
       <form class="form-horizontal" id="add-menu">
           {% csrf_token %}
           <div class="box-body">
               {% for field in form %}
                   {% if field.name == 'is_visible' %}
                       <div class="form-group">
   
                           <div class="col-sm-offset-2 col-sm-10">
   
                               <div class="checkbox">
                                   <label for="{{ field.id_for_label }}">{{ field }}{{ field.label }}</label>
                               </div>
                           </div>
   
                       </div>
                   {% else %}
                       <div class="form-group {% if field.errors %}has-error{% endif %}">
   
                           <label for="{{ field.id_for_label }}" class="col-sm-2 control-label">{{ field.label }}</label>
   
                           <div class="col-sm-10">
                               {% for error in field.errors %}
                                   <label class="control-label" for="{{ field.id_for_label }}">{{ error }}</label>
                               {% endfor %}
                               {% add_class field 'form-control' %}
                           </div>
                       </div>
                   {% endif %}
               {% endfor %}
   
           </div>
       </form>
   </div>
   <div class="modal-footer">
       <button type="button" class="btn btn-default pull-left" data-dismiss="modal">取消</button>
       <button type="button" class="btn btn-primary add">添加</button>
   </div>

四、添加菜单

1.业务流程分析

  • 接收表单参数
  • 校验表单参数
  • 校验成功保存菜单数据,创建菜单一对一关联权限对象,返回创建成功的json数据
  • 校验失败,返回渲染了错误信息的表单

2.接口设计

  1. 接口说明:
类目 说明
请求方法 POST
url定义 /admin/menu/
参数格式 表单参数
  1. 参数说明:
参数名 类型 是否必须 描述
name 字符串 菜单名
url 字符串 当前文章页数
order 整数 排序
parent 整数 父菜单id
icon 字符串 渲染图标类名
codename 字符串 权限码
is_visible 整数 是否可见
  1. 返回数据

    # 添加正常返回json数据
    {
    "errno": "0",
    "errmsg": "菜单添加成功!"
    }
    

    如果有错误,返回html表单

3.后端代码

  1. 视图

    # 在myadmin/views.py中的MenuAddView视图中添加post方法
    class MenuAddView(View):
        """
        添加菜单视图
        url:/admin/menu/
        """
    
        def get(self, request):
            form = MenuModelForm()
            return render(request, 'myadmin/menu/add_menu.html', context={'form': form})
    
        def post(self, request):
            form = MenuModelForm(request.POST)
            
            if form.is_valid():
                new_menu = form.save()
                content_type = ContentType.objects.filter(app_label='myadmin', model='menu').first()
                permission = Permission.objects.create(name=new_menu.name, content_type=content_type, codename=new_menu.codename)
                new_menu.permission = permission
                new_menu.save(update_fields=['permission'])
                return json_response(errmsg='菜单添加成功!')
            else:
                return render(request, 'myadmin/menu/add_menu.html', context={'form': form})
    

4.前端代码

  1. html

    <!-- 在 templates/myadmin/menu/add_menu.html 中引入js -->
    ...
    <script src="{% static 'js/myadmin/menu/add_menu.js' %}"></script>
    
  2. js

    // 创建static/js/myadmin/menu/add_menu.js
    $(() => {
        let $addBtn = $('button.add');          //  模态框中的添加按钮
        let $form = $('#add-menu');             //  模态矿中的表单
        let data = {};
        $addBtn.click(function () {
    
            $
                .ajax({
                    url: '/admin/menu/',
                    type: 'POST',
                    data: $form.serialize(),
                    // dataType: "json"
                })
                .done((res) => {
                    if (res.errno === '0') {
                        // 添加成功,关闭模态框,并刷新菜单列表
                        $('#modal-add').modal('hide').on('hidden.bs.modal', function (e) {
                            $('#content').load(
                                $('.sidebar-menu li.active a').data('url'),
                                (response, status, xhr) => {
                                    if (status !== 'success') {
                                        message.showError('服务器超时,请重试!')
                                    }
                                }
                            );
                        });
                        message.showSuccess(res.errmsg);
    
    
                    } else {
                        message.showError('添加菜单失败!');
                        // 更新模特框中的表单信息
                        $('#modal-add .modal-content').html(res)
                    }
                })
                .fail(() => {
                    message.showError('服务器超时,请重试');
                });
        });
    
    });
    

五、删除菜单

1.接口设计

  1. 接口说明:
类目 说明
请求方法 DELETE
url定义 /admin/menu/<int:menu_id>/
参数格式 路径参数
  1. 参数说明
参数名 类型 是否必须 描述
menu_id 整数 菜单id
  1. 返回值

    {
    "errno": "0",
    "errmsg": "删除菜单成功!"
    }
    

2.后端代码

  1. 视图

    # 在admin/views.py中创建一个MenuUpdateView视图
    class MenuUpdateView(View):
        """
        菜单管理视图
        url:/admin/menu/<int:menu_id>/
        """
    
        def delete(self, request, menu_id):
            menu = models.Menu.objects.filter(is_delete=False, id=menu_id)
            if menu:
                menu = menu[0]
                if menu.children.filter(is_delete=False).exists():
                    return json_response(errno=Code.DATAERR, errmsg='父菜单不能删除!')
                menu.is_delete = True
                menu.save(update_fields=['is_delete'])
                return json_response()
            else:
                return json_response(errno=Code.NODATA, errmsg='菜单不存在!')
    
    
  2. 路由

    # 在admin/urls.py中添加如下路由
    path('menu/<int:menu_id>/', views.MenuUpdateView.as_view(), name='menu_manage'),
    

3.前端代码

  1. html

    <!-- 
    修改 templates/admin/menu/menu_list.html 
    在content中,添加删除模态框
    然后引入menu.js
    -->
    {% block content %}
    ...
    ...
        <div class="modal modal-danger fade" id="modal-delete">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                            <span aria-hidden="true">&times;</span></button>
                        <h4 class="modal-title">警告</h4>
                    </div>
                    <div class="modal-body">
                        <p>One fine body&hellip;</p>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-outline pull-left" data-dismiss="modal">取消</button>
                        <button type="button" class="btn btn-outline delete-confirm">删除</button>
                    </div>
                </div>
                <!-- /.modal-content -->
            </div>
            <!-- /.modal-dialog -->
        </div>
        <!-- /.modal -->
    {% endblock %}
    {% block script %}
        <script src="{% static 'js/admin/menu/menu.js' %}"></script>
    {% endblock %}
    
  2. js

    // 创建 static/js/admin/menu/menu.js
    $(() => {
        let $editBtns = $('button.edit');
        let $deleteBtns = $('button.delete');       // 删除按钮
        menuId = 0;                                 // 被点击菜单id
        let $currentMenu = null;                    // 当前被点击菜单对象
    
        $deleteBtns.click(function () {
            let $this = $(this);
            $currentMenu = $this.parent().parent();
            menuId = $this.parent().data('id');
    
            let menuName = $this.parent().data('name');
    
            $('#modal-delete .modal-body p').html('确定删除菜单:《' + menuName + '》?');
            $('#modal-delete').modal('show');
            $('#modal-delete button.delete-confirm').click(() => {
                deleteMenu();
            })
    
        });
    
        // 删除菜单
        function deleteMenu() {
            $
                .ajax({
                    url: '/admin/menu/' + menuId + '/',
                    type: 'DELETE',
                    dataType: "json"
                })
                .done((res) => {
                    if (res.errno === '0') {
                        $('#modal-delete').modal('hide');
                        $('#modal-delete button.delete-confirm').unbind();
                        $currentMenu.remove();
                        message.showSuccess('删除成功!');
    
                    } else {
                        message.showError(res.errmsg)
                    }
                })
                .fail(() => {
                    message.showError('服务器超时,请重试!')
                });
    
        }
    
    });
    

六、编辑菜单页面

1. 接口设计

  1. 接口说明:
类目 说明
请求方法 GET
url定义 /admin/menu/<int:menu_id>
参数格式 路径参数
  1. 参数说明
参数名 类型 是否必须 描述
menu_id 整数 菜单id
  1. 返回数据

    html

2.后端代码

# 在admin/views.py中的MenuUpdateView视图中添加一个get方法
class MenuUpdateView(View):
    """
    菜单管理视图
    url:/admin/menu/<int:menu_id>/
    """

    def get(self, request, menu_id):
        menu = models.Menu.objects.filter(is_delete=False, id=menu_id).first()
        form = MenuModelForm(instance=menu)
        return render(request, 'admin/menu/update_menu.html', context={'form': form})

3.前端代码

  1. html

    <!-- 
    修改 templates/admin/menu/menu_list.html 
    在content中,添加修改模态框
    -->
    {% block content %}
     ...
        <!-- update modle -->
        <div class="modal fade" id="modal-update" role="dialog" aria-labelledby="myLargeModalLabel">
            <div class="modal-dialog">
                <div class="modal-content">
    
                </div>
                <!-- /.modal-content -->
            </div>
            <!-- /.modal-dialog -->
        </div>
        <!-- /.modal -->
    {% endblock %}
    
    <!-- 新建 templates/admin/menu/update_menu.html -->
    {% load admin_customer_tags %}
    {% load static %}
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            <span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title">修改菜单</h4>
    </div>
    <div class="modal-body">
        <form class="form-horizontal" id="update-menu">
            {% csrf_token %}
            <div class="box-body">
                {% for field in form %}
                    {% if field.name == 'is_visible' %}
                        <div class="form-group">
    
                            <div class="col-sm-offset-2 col-sm-10">
    
                                <div class="checkbox">
                                    <label for="{{ field.id_for_label }}">{{ field }}{{ field.label }}</label>
                                </div>
                            </div>
    
                        </div>
                    {% else %}
                        <div class="form-group {% if field.errors %}has-error{% endif %}">
    
                            <label for="{{ field.id_for_label }}" class="col-sm-2 control-label">{{ field.label }}</label>
    
                            <div class="col-sm-10">
                                {% for error in field.errors %}
                                    <label class="control-label" for="{{ field.id_for_label }}">{{ error }}</label>
                                {% endfor %}
                                {% add_class field 'form-control' %}
                            </div>
                        </div>
                    {% endif %}
                {% endfor %}
    
            </div>
        </form>
    </div>
    <div class="modal-footer">
        <button type="button" class="btn btn-default pull-left" data-dismiss="modal">取消</button>
        <button type="button" class="btn btn-primary update">修改</button>
    </div>
    
  2. js

    // 修改 static/js/admin/menu/menu.js 
    $(() => {
        let $editBtns = $('button.edit');
        let $deleteBtns = $('button.delete');       // 删除按钮
        menuId = 0;                                 // 被点击菜单id
        let $currentMenu = null;                    // 当前被点击菜单对象
    
        // 编辑菜单
        $editBtns.click(function () {
            let $this = $(this);
            $currentMenu = $this.parent().parent();
            menuId = $this.parent().data('id');
            $
                .ajax({
                    url: '/admin/menu/'+ menuId +'/',
                    type: 'get'
                })
                .done((res)=>{
                    $('#modal-update .modal-content').html(res);
                    $('#modal-update').modal('show')
                })
                .fail(()=>{
                    message.showError('服务器超时,请重试!')
                })
        });
    
        $deleteBtns.click(function () {
            let $this = $(this);
            $currentMenu = $this.parent().parent();
            menuId = $this.parent().data('id');
    
            let menuName = $this.parent().data('name');
    
            $('#modal-delete .modal-body p').html('确定删除菜单:《' + menuName + '》?');
            $('#modal-delete').modal('show');
            $('#modal-delete button.delete-confirm').click(() => {
                deleteMenu();
            })
    
        });
    
        // 删除菜单
        function deleteMenu() {
            $
                .ajax({
                    url: '/admin/menu/' + menuId + '/',
                    type: 'DELETE',
                    dataType: "json"
                })
                .done((res) => {
                    if (res.errno === '0') {
                        $('#modal-delete').modal('hide');
                        $('#modal-delete button.delete-confirm').unbind();
                        $currentMenu.remove();
                        message.showSuccess('删除成功!');
    
                    } else {
                        message.showError(res.errmsg)
                    }
                })
                .fail(() => {
                    message.showError('服务器超时,请重试!')
                });
        }
    });
    

七、编辑菜单

1.业务流程分析

  • 接收表单参数
  • 校验表单参数
  • 校验成功保存菜单,判断改动字段是否影响了权限,如果有影响,修改权限,返回json信息
  • 校验失败,返回包含错误信息的html

2.接口设计

  1. 接口说明:
类目 说明
请求方法 PUT
url定义 /admin/menu/<int:menu_id>
参数格式 路径参数+表单参数
  1. 参数说明:
参数名 类型 是否必须 描述
menu_id 整数 菜单id
name 字符串 菜单名
url 字符串 当前文章页数
order 整数 排序
parent 整数 父菜单id
icon 字符串 渲染图标类名
codename 字符串 权限码
is_visible 整数 是否可见
  1. 返回数据

    # 添加正常返回json数据
    {
    "errno": "0",
    "errmsg": "菜单修改成功!"
    }
    

    如果有错误,返回html表单

3.后端代码

  1. 视图

    # 在admin/views.py中的MenuUpdateView视图中添加一个put方法
    class MenuUpdateView(View):
        """
        菜单管理视图
        url:/admin/menu/<int:menu_id>/
        """
    ...
    
        def put(self, request, menu_id):
            menu = models.Menu.objects.filter(is_delete=False, id=menu_id).first()
            put = QueryDict(request.body)
            form = MenuModelForm(put, instance=menu)
            if form.is_valid():
                obj = form.save()
                if 'name' in form.changed_data:
                    obj.permission.name = obj.name
                if 'codename' in form.changed_data:
                    obj.permission.codename = obj.codename
                obj.permission.save()
                return json_response(errmsg='菜单修改成功!')
            else:
                return render(request, 'admin/menu/update_menu.html', context={'form': form})
    ...
    
    

4.前端代码

  1. html
<!-- 在 templates/admin/menu/update_menu.html 
中引入update_menu.js
-->
...
<script src="{% static 'js/admin/menu/update_menu.js' %}"></script>
  1. js

    $(()=>{
        let $updateBtn = $('#modal-update button.update');
        let $form = $('#update-menu');
        let data = {};
        $updateBtn.click(function () {
            $.each($form.serializeArray(), function () {
                data[this.name] = this.value
            });
            $
                .ajax({
                    url: '/admin/menu/' + menuId + '/',
                    type: 'PUT',
                    data: data,
                    // dataType: "json"
                })
                .done((res) => {
                    if (res.errno === '0') {
                        $('#modal-update').modal('hide').on('hidden.bs.modal', function (e) {
                            $('#content').load(
                                $('.sidebar-menu li.active a').data('url'),
                                (response, status, xhr) => {
                                    if (status !== 'success') {
                                        message.showError('服务器超时,请重试!')
                                    }
                                }
                            );
                        });
                        message.showSuccess(res.errmsg);
    
    
                    } else {
                        message.showError('修改菜单失败!');
                        $('#modal-update .modal-content').html(res)
                    }
                })
                .fail(() => {
                    message.showError('服务器超时,请重试');
                });
        });
    });
    

八、整合后台首页面菜单加载

1. 后端代码

  1. 视图

    class IndexView(LoginRequiredMixin, View):
        """
        后台首页视图
        """
    
        def get(self, request):
    
            objs = models.Menu.objects.only('name', 'url', 'icon', 'permission__codename',
                                            'permission__content_type__app_label').select_related(
                'permission__content_type').filter(is_delete=False, is_visible=True, parent=None)
            has_permissions = request.user.get_all_permissions()
            menus = []
            for menu in objs:
                if '%s.%s' % (menu.permission.content_type.app_label, menu.permission.codename) in has_permissions:
                    temp = {
                        'name': menu.name,
                        'icon': menu.icon
                    }
    
                    children = menu.children.filter(is_delete=False, is_visible=True)
                    if children:
                        temp['children'] = []
                        for child in children:
                            if '%s.%s' % (child.permission.content_type.app_label, child.permission.codename) in has_permissions:
                                temp['children'].append({
                                    'name': child.name,
                                    'url': child.url
                                })
                    else:
                        if not menu.url:
                            continue
                        temp['url'] = menu.url
                    menus.append(temp)
            print(menus)
         return render(request, 'admin/index.html', context={'menus': menus})
    

效果如图:
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容