django項目--菜單管理

后臺菜單管理功能

一、業(yè)務功能分析

1. 業(yè)務需求分析

后臺首頁菜單根據(jù)用戶權限動態(tài)生成葫笼,不同菜單對應不同的功能視圖。菜單的增刪改查哲泊。

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.業(yè)務流程分析

  1. 獲取未刪除,的一級菜單
  2. 根據(jù)一級菜單獲取未刪除的二級菜單
  3. 渲染頁面

2.接口設計

  1. 接口說明
類目 說明
請求方法 GET
url定義 /admin/menus/
參數(shù)格式 無參數(shù)
  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

<!-- 創(chuàng)建templates/myadmin/menu/menu_list.html-->
{% extends 'myadmin/base/content_base.html' %}
{% load static %}
{% block page_header %}系統(tǒng)設置{% 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/
參數(shù)格式 無參數(shù)
  1. 返回數(shù)據(jù)

    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下創(chuàng)建templatetags包喳魏,在其中創(chuàng)建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 %}系統(tǒng)設置{% 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.業(yè)務流程分析

  • 接收表單參數(shù)
  • 校驗表單參數(shù)
  • 校驗成功保存菜單數(shù)據(jù),創(chuàng)建菜單一對一關聯(lián)權限對象刺彩,返回創(chuàng)建成功的json數(shù)據(jù)
  • 校驗失敗迷郑,返回渲染了錯誤信息的表單

2.接口設計

  1. 接口說明:
類目 說明
請求方法 POST
url定義 /admin/menu/
參數(shù)格式 表單參數(shù)
  1. 參數(shù)說明:
參數(shù)名 類型 是否必須 描述
name 字符串 菜單名
url 字符串 當前文章頁數(shù)
order 整數(shù) 排序
parent 整數(shù) 父菜單id
icon 字符串 渲染圖標類名
codename 字符串 權限碼
is_visible 整數(shù) 是否可見
  1. 返回數(shù)據(jù)

    # 添加正常返回json數(shù)據(jù)
    {
    "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

    // 創(chuàng)建static/js/myadmin/menu/add_menu.js
    $(() => {
        let $addBtn = $('button.add');          //  模態(tài)框中的添加按鈕
        let $form = $('#add-menu');             //  模態(tài)礦中的表單
        let data = {};
        $addBtn.click(function () {
    
            $
                .ajax({
                    url: '/admin/menu/',
                    type: 'POST',
                    data: $form.serialize(),
                    // dataType: "json"
                })
                .done((res) => {
                    if (res.errno === '0') {
                        // 添加成功,關閉模態(tài)框三幻,并刷新菜單列表
                        $('#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>/
參數(shù)格式 路徑參數(shù)
  1. 參數(shù)說明
參數(shù)名 類型 是否必須 描述
menu_id 整數(shù) 菜單id
  1. 返回值

    {
    "errno": "0",
    "errmsg": "刪除菜單成功!"
    }
    

2.后端代碼

  1. 視圖

    # 在admin/views.py中創(chuàng)建一個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中,添加刪除模態(tài)框
    然后引入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

    // 創(chuàng)建 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>
參數(shù)格式 路徑參數(shù)
  1. 參數(shù)說明
參數(shù)名 類型 是否必須 描述
menu_id 整數(shù) 菜單id
  1. 返回數(shù)據(jù)

    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中栈虚,添加修改模態(tài)框
    -->
    {% 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.業(yè)務流程分析

  • 接收表單參數(shù)
  • 校驗表單參數(shù)
  • 校驗成功保存菜單鬓照,判斷改動字段是否影響了權限,如果有影響孤紧,修改權限豺裆,返回json信息
  • 校驗失敗,返回包含錯誤信息的html

2.接口設計

  1. 接口說明:
類目 說明
請求方法 PUT
url定義 /admin/menu/<int:menu_id>
參數(shù)格式 路徑參數(shù)+表單參數(shù)
  1. 參數(shù)說明:
參數(shù)名 類型 是否必須 描述
menu_id 整數(shù) 菜單id
name 字符串 菜單名
url 字符串 當前文章頁數(shù)
order 整數(shù) 排序
parent 整數(shù) 父菜單id
icon 字符串 渲染圖標類名
codename 字符串 權限碼
is_visible 整數(shù) 是否可見
  1. 返回數(shù)據(jù)

    # 添加正常返回json數(shù)據(jù)
    {
    "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})
    

效果如圖:
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末钾菊,一起剝皮案震驚了整個濱河市帅矗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌煞烫,老刑警劉巖浑此,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滞详,居然都是意外死亡凛俱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門料饥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒲犬,“玉大人,你說我怎么就攤上這事岸啡≡#” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵巡蘸,是天一觀的道長奋隶。 經常有香客問我,道長悦荒,這世上最難降的妖魔是什么唯欣? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮逾冬,結果婚禮上黍聂,老公的妹妹穿的比我還像新娘躺苦。我一直安慰自己,他們只是感情好产还,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布匹厘。 她就那樣靜靜地躺著,像睡著了一般脐区。 火紅的嫁衣襯著肌膚如雪愈诚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天牛隅,我揣著相機與錄音炕柔,去河邊找鬼。 笑死媒佣,一個胖子當著我的面吹牛匕累,可吹牛的內容都是我干的。 我是一名探鬼主播默伍,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼欢嘿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了也糊?” 一聲冷哼從身側響起炼蹦,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狸剃,沒想到半個月后掐隐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡钞馁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年虑省,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片指攒。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡慷妙,死狀恐怖,靈堂內的尸體忽然破棺而出允悦,到底是詐尸還是另有隱情,我是刑警寧澤虑啤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布隙弛,位于F島的核電站,受9級特大地震影響狞山,放射性物質發(fā)生泄漏全闷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一萍启、第九天 我趴在偏房一處隱蔽的房頂上張望总珠。 院中可真熱鬧屏鳍,春花似錦、人聲如沸局服。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽淫奔。三九已至山涡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唆迁,已是汗流浹背鸭丛。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留唐责,地道東北人鳞溉。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像鼠哥,于是被迫代替她去往敵國和親熟菲。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內容