[django项目] 后台菜单管理功能

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/makesomethings/article/details/100531608

后台菜单管理功能

菜单的管理功能其实就是, 对菜单的增删改查

I. 业务功能分析

1>业务需求分析

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

菜单的增删改查。

2>功能分析

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

3>模型设计

3.1>字段分析
  • name, 菜单名
  • url, 菜单的路由
  • parent, 父菜单的id
  • order, 排序
  • permission, 访问该菜单的权限名
  • icon, 菜单显示的icon
  • codename, 菜单的权限码
  • is_visible, 是否可见
3.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)

<span class="token keyword">class</span> <span class="token class-name">Meta</span><span class="token punctuation">:</span>
    ordering <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'-order'</span><span class="token punctuation">]</span>
    db_table <span class="token operator">=</span> <span class="token string">'tb_menu'</span>
    verbose_name <span class="token operator">=</span> <span class="token string">'菜单'</span>
    verbose_name_plural <span class="token operator">=</span> verbose_name

<span class="token keyword">def</span> <span class="token function">__str__</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">return</span> self<span class="token punctuation">.</span>name
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

模型创建后记得迁移, 项目到目前的阶段, 数据库的内容开始变得比较复杂了, 所以该迁移的时候一定不要落下

II. 菜单列表

1>业务流程分析

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

2>接口设计

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

    html

3>后端代码

3.1>视图
#  myadmin/views.py下定义如下视图:
class MenuListView(View):
    """
    菜单列表视图
    url:/admin/menu_list/
    """
    def get(self, request):
        # 为了便于后续的修改, 需要展示被逻辑删除的菜单,
        # 因此filter的is_delete属性就不许要加了
        menus = models.Menu.objects.only(
            'name', 'url', 'icon', 'is_visible', 'order', 'codename'
        ).filter(parent=None)
        # parent=None表示没有父菜单, 即一级菜单
        return render(request, 'myadmin/menu/menu_list.html', context={'menus': menus})

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
#  myadmin/views.py中修改菜单管理对应的路由:
class IndexView(View):
    """
    后台首页视图
    """
    def get(self, request):
        menus = [
            {...},
            {...},
            {...},
            {...},
            {...},
            {
                "name": "系统设置",
                "icon": "fa-cogs",
                "children": [
                    {...},
                    {...},
                    {
                        "name": "菜单管理",
                        "url": "myadmin:menu_list"
                    },
                    {...}
                ]
            }
    <span class="token punctuation">]</span>
    <span class="token keyword">return</span> render<span class="token punctuation">(</span>request<span class="token punctuation">,</span> <span class="token string">'myadmin/index.html'</span><span class="token punctuation">,</span> context<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">'menus'</span><span class="token punctuation">:</span> menus<span class="token punctuation">}</span><span class="token punctuation">)</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
3.2>路由
# admin/urls.py中添加如下路由
path('menu_list/', views.MenuListView.as_view(), name='menu_list'),

 
 
  • 1
  • 2

4>前端代码

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 %}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5

创建好后记得重启一下django的服务哦

页面效果:

[外链图片转存失败(img-U73ceLqz-1567554944282)(django%E9%A1%B9%E7%9B%AE-%E5%90%8E%E5%8F%B0%E7%AE%A1%E7%90%86.assets/1567311498712.png)]

可以打开这个界面, 就说明路由和视图配置好了

接下来将列表填充到这个页面, 我们可以使用AdminLTE为用户提供的表格模板:

[外链图片转存失败(img-ZlwaLcOP-1567554944283)(django%E9%A1%B9%E7%9B%AE-%E5%90%8E%E5%8F%B0%E7%AE%A1%E7%90%86.assets/1567311671862.png)]

这个页面上有很多类型的表格, 修改前端代码

{% 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>
<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 role=row>
<!-- 列表字段 -->
<th>菜单</th>
<th>子菜单</th>
<th>路由地址</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>
<!-- /.box-body -->
</div>
{% endblock %}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87

注意父菜单和子菜单循环体中的那两个<td></td>标签, 这样做得目的是为了更好的分辨父菜单和子菜单

III. 添加菜单页面

功能概述: 点击添加菜单按钮, 弹出新增菜单窗口, 输入信息提交, 即可添加到菜单列表中

1>接口设计

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

    html

2>后端代码

2.1>视图
# 在myadmin/views.py中添加如下视图
class MenuAddView(View):
    """
    添加菜单视图
    url:/admin/menu/
    """
<span class="token keyword">def</span> <span class="token function">get</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> request<span class="token punctuation">)</span><span class="token punctuation">:</span>

    form <span class="token operator">=</span> MenuModelForm<span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> render<span class="token punctuation">(</span>request<span class="token punctuation">,</span> <span class="token string">'myadmin/menu/add_menu.html'</span><span class="token punctuation">,</span> context<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">'form'</span><span class="token punctuation">:</span> form<span class="token punctuation">}</span><span class="token punctuation">)</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
2.2>路由
# 在myadmin/urls.py中添加如下路由
path('menu/', views.MenuAddView.as_view(), name='add_menu')

 
 
  • 1
  • 2
2.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=‘父菜单’)

<span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> <span class="token operator">*</span>args<span class="token punctuation">,</span> <span class="token operator">**</span>kwargs<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token builtin">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>__init__<span class="token punctuation">(</span><span class="token operator">*</span>args<span class="token punctuation">,</span> <span class="token operator">**</span>kwargs<span class="token punctuation">)</span>
    self<span class="token punctuation">.</span>fields<span class="token punctuation">[</span><span class="token string">'parent'</span><span class="token punctuation">]</span><span class="token punctuation">.</span>queryset <span class="token operator">=</span> Menu<span class="token punctuation">.</span>objects<span class="token punctuation">.</span><span class="token builtin">filter</span><span class="token punctuation">(</span>is_delete<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">,</span> is_visible<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> parent<span class="token operator">=</span><span class="token boolean">None</span><span class="token punctuation">)</span>
    <span class="token comment"># https://docs.djangoproject.com/en/2.2/ref/forms/fields/#fields-which-handle-relationships</span>

<span class="token keyword">class</span> <span class="token class-name">Meta</span><span class="token punctuation">:</span>
    model <span class="token operator">=</span> Menu
    fields <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'name'</span><span class="token punctuation">,</span> <span class="token string">'url'</span><span class="token punctuation">,</span> <span class="token string">'order'</span><span class="token punctuation">,</span> <span class="token string">'parent'</span><span class="token punctuation">,</span> <span class="token string">'icon'</span><span class="token punctuation">,</span> <span class="token string">'codename'</span><span class="token punctuation">,</span> <span class="token string">'is_visible'</span><span class="token punctuation">]</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
2.4>自定义标签

为了在渲染表单是能加入自定义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})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3>前端代码

3.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">...</div>
        <!-- /.box-header -->
        <div class="box-body">...</div>
    </div>
<span class="token comment">&lt;!-- add modle --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>modal fade<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>modal-add<span class="token punctuation">"</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>dialog<span class="token punctuation">"</span></span> <span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>modal-dialog<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>modal-content<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token comment">&lt;!-- /.modal-content --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- /.modal-dialog --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!-- /.modal --&gt;</span>

{% endblock %}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

弹出窗口我们选用表单的形式来完成, 因此这里单独创建一个模型, 方便渲染

这里的模型来自Bootstarp

   <!-- 新建 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">
                       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>col-sm-offset-2 col-sm-10<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

                           <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                               <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{{ field.id_for_label }}<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>{{ field }}{{ field.label }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
                           <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
                       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

                   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
               {% else %}
                   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>form-group {% if field.errors %}has-error{% endif %}<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

                       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{{ field.id_for_label }}<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>col-sm-2 control-label<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>{{ field.label }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>

                       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>col-sm-10<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                           {% for error in field.errors %}
                               <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>control-label<span class="token punctuation">"</span></span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{{ field.id_for_label }}<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>{{ error }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
                           {% endfor %}
                           {% add_class field 'form-control' %}
                       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
                   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
               {% endif %}
           {% endfor %}

       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>

</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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

根据官方文档我们还需要加一个href=#foo(路由地址)属性到添加菜单按钮标签中

<div class="box-tools">
	<button type="button" class="btn btn-primary btn-sm" 
            data-toggle="modal" data-target="#modal-add" 
            href="/admin/add_menu/">添加菜单</button>
</div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

页面效果:

[外链图片转存失败(img-QtGhDXrh-1567554944294)(django%E9%A1%B9%E7%9B%AE-%E5%90%8E%E5%8F%B0%E7%AE%A1%E7%90%86.assets/)]

IIII. 添加菜单

1>业务流程分析

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

2>接口设计

2.1>接口说明:
类目说明
请求方法POST
url定义/admin/menu/
参数格式表单参数
2.2>参数说明:
参数名类型是否必须描述
name字符串菜单名
url字符串当前文章页数
order整数排序
parent整数父菜单id
icon字符串渲染图标类名
codename字符串权限码
is_visible整数是否可见
2.3>返回数据
# 添加正常返回json数据
{
"errno": "0",
"errmsg": "菜单添加成功!"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果有错误,返回html表单

3>后端代码

3.1>视图
# 在myadmin/views.py中的MenuAddView视图中添加post方法
class MenuAddView(View):
    """
    添加菜单视图
    url:/admin/menu/
    """
<span class="token keyword">def</span> <span class="token function">get</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> request<span class="token punctuation">)</span><span class="token punctuation">:</span>
    form <span class="token operator">=</span> MenuModelForm<span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">return</span> render<span class="token punctuation">(</span>request<span class="token punctuation">,</span> <span class="token string">'myadmin/menu/add_menu.html'</span><span class="token punctuation">,</span> context<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">'form'</span><span class="token punctuation">:</span> form<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">def</span> <span class="token function">post</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> request<span class="token punctuation">)</span><span class="token punctuation">:</span>
    form <span class="token operator">=</span> MenuModelForm<span class="token punctuation">(</span>request<span class="token punctuation">.</span>POST<span class="token punctuation">)</span>
    
    <span class="token keyword">if</span> form<span class="token punctuation">.</span>is_valid<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
        new_menu <span class="token operator">=</span> form<span class="token punctuation">.</span>save<span class="token punctuation">(</span><span class="token punctuation">)</span>
        content_type <span class="token operator">=</span> ContentType<span class="token punctuation">.</span>objects<span class="token punctuation">.</span><span class="token builtin">filter</span><span class="token punctuation">(</span>app_label<span class="token operator">=</span><span class="token string">'myadmin'</span><span class="token punctuation">,</span> model<span class="token operator">=</span><span class="token string">'menu'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>first<span class="token punctuation">(</span><span class="token punctuation">)</span>
        permission <span class="token operator">=</span> Permission<span class="token punctuation">.</span>objects<span class="token punctuation">.</span>create<span class="token punctuation">(</span>name<span class="token operator">=</span>new_menu<span class="token punctuation">.</span>name<span class="token punctuation">,</span> content_type<span class="token operator">=</span>content_type<span class="token punctuation">,</span> codename<span class="token operator">=</span>new_menu<span class="token punctuation">.</span>codename<span class="token punctuation">)</span>
        new_menu<span class="token punctuation">.</span>permission <span class="token operator">=</span> permission
        new_menu<span class="token punctuation">.</span>save<span class="token punctuation">(</span>update_fields<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">'permission'</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
        <span class="token keyword">return</span> json_response<span class="token punctuation">(</span>errmsg<span class="token operator">=</span><span class="token string">'菜单添加成功!'</span><span class="token punctuation">)</span>
    <span class="token keyword">else</span><span class="token punctuation">:</span>
        <span class="token keyword">return</span> render<span class="token punctuation">(</span>request<span class="token punctuation">,</span> <span class="token string">'myadmin/menu/add_menu.html'</span><span class="token punctuation">,</span> context<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">'form'</span><span class="token punctuation">:</span> form<span class="token punctuation">}</span><span class="token punctuation">)</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

4>前端代码

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


            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
                message<span class="token punctuation">.</span><span class="token function">showError</span><span class="token punctuation">(</span><span class="token string">'添加菜单失败!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 更新模特框中的表单信息</span>
                <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'#modal-add .modal-content'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">html</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">fail</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            message<span class="token punctuation">.</span><span class="token function">showError</span><span class="token punctuation">(</span><span class="token string">'服务器超时,请重试'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

});

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
4.2>html
<!-- 在 templates/myadmin/menu/add_menu.html 中引入js -->
...
<script src="{% static 'js/myadmin/menu/add_menu.js' %}"></script>
  • 1
  • 2
  • 3
  • 4

V. 删除菜单

1>接口设计

1.1>接口说明:
类目说明
请求方法DELETE
url定义/admin/menu/<int:menu_id>/
参数格式路径参数
1.2>参数说明
参数名类型是否必须描述
menu_id整数菜单id
1.3>返回值
{
"errno": "0",
"errmsg": "删除菜单成功!"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

后台展示的菜单不重要,所以我们不用逻辑删除菜单,而是采用真删除

2>后端代码

2.1>视图
# 在admin/views.py中创建一个MenuUpdateView视图
class MenuUpdateView(View):
    """
    菜单管理视图,delete删除菜单
    url:/admin/menu/<int:menu_id>/
    """
    def delete(self, request, menu_id):
        # 获取到需要删除的菜单
        menu = models.Menu.objects.only('name').filter(id=menu_id)
    <span class="token keyword">if</span> menu<span class="token punctuation">:</span>
        menu <span class="token operator">=</span> menu<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span>
        <span class="token comment"># 判断是是否为父菜单</span>
        <span class="token keyword">if</span> menu<span class="token punctuation">.</span>children<span class="token punctuation">.</span><span class="token builtin">filter</span><span class="token punctuation">(</span>is_delete<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">)</span><span class="token punctuation">.</span>exists<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
            <span class="token keyword">return</span> json_response<span class="token punctuation">(</span>errno<span class="token operator">=</span>Code<span class="token punctuation">.</span>DATAERR<span class="token punctuation">,</span> errmsg<span class="token operator">=</span><span class="token string">'父菜单不能删除!'</span><span class="token punctuation">)</span>
        <span class="token comment"># 将menu模型中的permission设置为CASCADE级联删除, 就可以使其在被删除的时候同时删除当条菜单</span>
        menu<span class="token punctuation">.</span>permission<span class="token punctuation">.</span>delete<span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token comment"># menu.delete()</span>
        <span class="token keyword">return</span> json_response<span class="token punctuation">(</span>errmsg<span class="token operator">=</span><span class="token string">'删除菜单:%s成功'</span> <span class="token operator">%</span> menu<span class="token punctuation">.</span>name<span class="token punctuation">)</span>
    <span class="token keyword">else</span><span class="token punctuation">:</span>
        <span class="token keyword">return</span> json_response<span class="token punctuation">(</span>errno<span class="token operator">=</span>Code<span class="token punctuation">.</span>NODATA<span class="token punctuation">,</span> errmsg<span class="token operator">=</span><span class="token string">'菜单不存在!'</span><span class="token punctuation">)</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
2.2>路由
# 在admin/urls.py中添加如下路由
path('menu/<int:menu_id>/', views.MenuUpdateView.as_view(), name='menu_manage'),
  • 1
  • 2
  • 3
  • 4

3>前端代码

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_list.js' %}"></script>
{% endblock %}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

记得再去content_base里挖一个script的block

3.2>js
// 创建 static/js/admin/menu/menu_list.js
$(() => {
    let $deleteBtns = $('button.delete');	// 删除按钮
    menuId = 0;		// 被点击菜单id
    let $currentMenu = null;	// 当前被点击菜单对象, 也就是对应的tr标签(表格中的一行)
$deleteBtns<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> $<span class="token keyword">this</span> <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    $currentMenu <span class="token operator">=</span> $<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">parent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">parent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    menuId <span class="token operator">=</span> $<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">parent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token string">'id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>	<span class="token comment">// 菜单id</span>
    <span class="token keyword">let</span> menuName <span class="token operator">=</span> $<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">parent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token string">'name'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>	<span class="token comment">// 菜单名</span>
    
    <span class="token comment">// 改变模态框的显示内容</span>
    <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'#modal-delete .modal-body p'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">html</span><span class="token punctuation">(</span><span class="token string">'确定删除菜单: " + menuName + " ?'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token comment">// 显示 模态框</span>
    <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'#modal-delete'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">modal</span><span class="token punctuation">(</span><span class="token string">'show'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'#modal-delete button.delete-confirm'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token function">deleteMenu</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 删除菜单的函数</span>
<span class="token keyword">function</span> <span class="token function">deleteMenu</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    $
        <span class="token punctuation">.</span><span class="token function">ajax</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
            url<span class="token punctuation">:</span> <span class="token string">'/admin/menu/'</span> <span class="token operator">+</span> menuId <span class="token operator">+</span> <span class="token string">'/'</span><span class="token punctuation">,</span>
            type<span class="token punctuation">:</span> <span class="token string">'DELETE'</span><span class="token punctuation">,</span>
            dataType<span class="token punctuation">:</span> <span class="token string">'json'</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">done</span><span class="token punctuation">(</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span>errno <span class="token operator">===</span> <span class="token string">'0'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>	<span class="token comment">// errno为0代表成功</span>
                <span class="token comment">// 关闭模态框</span>
                <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'#modal-delete'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">modal</span><span class="token punctuation">(</span><span class="token string">'hide'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 删除菜单元素</span>
                $currentMenu<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                message<span class="token punctuation">.</span><span class="token function">showSuccess</span><span class="token punctuation">(</span><span class="token string">'删除成功!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>	<span class="token comment">// 否则就表示出现了问题</span>
                message<span class="token punctuation">.</span><span class="token function">showError</span><span class="token punctuation">(</span>res<span class="token punctuation">.</span>errmsg<span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">fail</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            message<span class="token punctuation">.</span><span class="token function">showError</span><span class="token punctuation">(</span><span class="token string">'服务器超时请重试!'</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

});

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

因为delete方法会改变数据库,所以需要csrftoken,在js/myadmin/menu.js中添加如下代码

   function getCookie(name) {
           var cookieValue = null;
           if (document.cookie && document.cookie !== '') {
               var cookies = document.cookie.split(';');
               for (var i = 0; i < cookies.length; i++) {
                   var cookie = cookies[i].trim();
                   // Does this cookie string begin with the name we want?
                   if (cookie.substring(0, name.length + 1) === (name + '=')) {
                       cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                       break;
                   }
               }
           }
           return cookieValue;
       }
   <span class="token keyword">function</span> <span class="token function">csrfSafeMethod</span><span class="token punctuation">(</span>method<span class="token punctuation">)</span> <span class="token punctuation">{</span>
       <span class="token comment">// these HTTP methods do not require CSRF protection</span>
       <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token regex">/^(GET|HEAD|OPTIONS|TRACE)$/</span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>method<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

   $<span class="token punctuation">.</span><span class="token function">ajaxSetup</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
       beforeSend<span class="token punctuation">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span>xhr<span class="token punctuation">,</span> settings<span class="token punctuation">)</span> <span class="token punctuation">{</span>
           <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">csrfSafeMethod</span><span class="token punctuation">(</span>settings<span class="token punctuation">.</span>type<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>crossDomain<span class="token punctuation">)</span> <span class="token punctuation">{</span>
               xhr<span class="token punctuation">.</span><span class="token function">setRequestHeader</span><span class="token punctuation">(</span><span class="token string">"X-CSRFToken"</span><span class="token punctuation">,</span> <span class="token function">getCookie</span><span class="token punctuation">(</span><span class="token string">'csrftoken'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
           <span class="token punctuation">}</span>
       <span class="token punctuation">}</span>
   <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

记得前端要加上{% csrf_token %}, 关于cookie还有一点就是

如果你先执行添加菜单再执行删除的话, 即使不加{% csrf_token %}也会执行删除

这是因为执行添加的话就会生成cookie, 已经有了当前页面的cookie, 其他需要cookie的请求(post,put,delete)都可以执行

VI. 编辑菜单页面

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>/
    """
<span class="token keyword">def</span> <span class="token function">get</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> request<span class="token punctuation">,</span> menu_id<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token comment"># 找到需要编辑的菜单</span>
    menu <span class="token operator">=</span> models<span class="token punctuation">.</span>Menu<span class="token punctuation">.</span>objects<span class="token punctuation">.</span><span class="token builtin">filter</span><span class="token punctuation">(</span><span class="token builtin">id</span><span class="token operator">=</span>menu_id<span class="token punctuation">)</span><span class="token punctuation">.</span>first<span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token comment"># 使用之前定义的表单</span>
    form <span class="token operator">=</span> MenuModelForm<span class="token punctuation">(</span>instance<span class="token operator">=</span>menu<span class="token punctuation">)</span>
    <span class="token keyword">return</span> render<span class="token punctuation">(</span>request<span class="token punctuation">,</span> <span class="token string">'myadmin/menu/update_menu.html'</span><span class="token punctuation">,</span> context<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">'form'</span><span class="token punctuation">:</span> form<span class="token punctuation">}</span><span class="token punctuation">)</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3>前端代码

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">
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
        <span class="token comment">&lt;!-- /.modal-content --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- /.modal-dialog --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!-- /.modal --&gt;</span>

{% endblock %}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

编辑的模态框其实和添加模态框很相似, 是可以进行代码复用的, 这个我们后面再说, 先完成功能

   <!-- 新建 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">
                       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>col-sm-offset-2 col-sm-10<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

                           <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>checkbox<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                               <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{{ field.id_for_label }}<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>{{ field }}{{ field.label }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
                           <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
                       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>

                   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
               {% else %}
                   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>form-group {% if field.errors %}has-error{% endif %}<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>

                       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{{ field.id_for_label }}<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>col-sm-2 control-label<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>{{ field.label }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>

                       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>col-sm-10<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
                           {% for error in field.errors %}
                               <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>control-label<span class="token punctuation">"</span></span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{{ field.id_for_label }}<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>{{ error }}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
                           {% endfor %}
                           {% add_class field 'form-control' %}
                       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
                   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
               {% endif %}
           {% endfor %}

       <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">&gt;</span></span>

</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>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
3.2>js
// 修改 static/js/admin/menu/menu_list.js 
$(() => {
    let $editBtns = $('button.edit');           // 编辑按钮
    let $deleteBtns = $('button.delete');       // 删除按钮
    menuId = 0;      // 被点击菜单id,要设置为全局变量, 不加let就行
    let $currentMenu = null;                    // 当前被点击菜单对象
$deleteBtns<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'#modal-delete button.delete-confirm'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 删除菜单的函数</span>
<span class="token keyword">function</span> <span class="token function">deleteMenu</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span>

<span class="token comment">// 编辑菜单</span>
$editBtns<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> $<span class="token keyword">this</span> <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    $currentMenu <span class="token operator">=</span> $<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">parent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">parent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    menuId <span class="token operator">=</span> $<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">parent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token string">'id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    $
        <span class="token punctuation">.</span><span class="token function">ajax</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
            url<span class="token punctuation">:</span> <span class="token string">'/admin/menu/'</span> <span class="token operator">+</span> menuId <span class="token operator">+</span> <span class="token string">'/'</span><span class="token punctuation">,</span>
            type<span class="token punctuation">:</span> <span class="token string">'GET'</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">done</span><span class="token punctuation">(</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>	<span class="token comment">// res是ajax请求回来的数据</span>
            <span class="token comment">// 改变模态框的html</span>
            <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'#modal-update .modal-content'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">html</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 显示模态框</span>
            <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'#modal-update'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">modal</span><span class="token punctuation">(</span><span class="token string">'show'</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">fail</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
            message<span class="token punctuation">.</span><span class="token function">showError</span><span class="token punctuation">(</span><span class="token string">'服务器超时,请重试!'</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

});

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

VII. 编辑菜单

完成了页面, 接下来就是点击修改, 再发送一个ajax回去, 我们需要再写一个后台接收编辑数据

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": "菜单修改成功!"
    }
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果有错误,返回html表单

3>后端代码

3.1>视图
# 在admin/views.py中的MenuUpdateView视图中添加一个put方法
class MenuUpdateView(View):
    """
    菜单管理视图
    url:/admin/menu/<int:menu_id>/
    """
...
<span class="token keyword">def</span> <span class="token function">put</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> request<span class="token punctuation">,</span> menu_id<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token comment"># 获取到需要修改的菜单</span>
    menu <span class="token operator">=</span> models<span class="token punctuation">.</span>Menu<span class="token punctuation">.</span>objects<span class="token punctuation">.</span><span class="token builtin">filter</span><span class="token punctuation">(</span><span class="token builtin">id</span><span class="token operator">=</span>menu_id<span class="token punctuation">)</span><span class="token punctuation">.</span>first<span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">if</span> <span class="token operator">not</span> menu<span class="token punctuation">:</span>
        <span class="token keyword">return</span> json_response<span class="token punctuation">(</span>errno<span class="token operator">=</span>Code<span class="token punctuation">.</span>NODATA<span class="token punctuation">,</span> errmsg<span class="token operator">=</span><span class="token string">'菜单不存在!'</span><span class="token punctuation">)</span>
    <span class="token comment"># 获取put请求的数据, request.body就是前端表单中所有的输入</span>
    put_data <span class="token operator">=</span> QueryDict<span class="token punctuation">(</span>request<span class="token punctuation">.</span>body<span class="token punctuation">)</span>
    <span class="token comment"># QueryDict这个方法会将body转换成一个类字典对象</span>
    form <span class="token operator">=</span> MenuModelForm<span class="token punctuation">(</span>put_data<span class="token punctuation">,</span> instance<span class="token operator">=</span>menu<span class="token punctuation">)</span>
    <span class="token keyword">if</span> form<span class="token punctuation">.</span>is_valid<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
        obj <span class="token operator">=</span> form<span class="token punctuation">.</span>save<span class="token punctuation">(</span><span class="token punctuation">)</span>	<span class="token comment"># 拿到一个新的menu对象,命名为obj</span>
        <span class="token comment"># 检查修改了的字段是否和权限有关</span>
        flag <span class="token operator">=</span> <span class="token boolean">False</span>
        <span class="token keyword">if</span> <span class="token string">'name'</span> <span class="token keyword">in</span> form<span class="token punctuation">.</span>changed_data<span class="token punctuation">:</span>
            <span class="token comment"># changed_data会返回一个列表,包含当前修改了的字段</span>
            <span class="token comment"># 将已有的name更新为最新的</span>
            obj<span class="token punctuation">.</span>permission<span class="token punctuation">.</span>name <span class="token operator">=</span> obj<span class="token punctuation">.</span>name
            flag <span class="token operator">=</span> <span class="token boolean">True</span>
        <span class="token keyword">if</span> <span class="token string">'codename'</span> <span class="token keyword">in</span> form<span class="token punctuation">.</span>changed_data<span class="token punctuation">:</span>
            obj<span class="token punctuation">.</span>permission<span class="token punctuation">.</span>codename <span class="token operator">=</span> obj<span class="token punctuation">.</span>name
            flag <span class="token operator">=</span> <span class="token boolean">True</span>
        <span class="token keyword">if</span> flag<span class="token punctuation">:</span>
            obj<span class="token punctuation">.</span>permission<span class="token punctuation">.</span>save<span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token keyword">return</span> json_response<span class="token punctuation">(</span>errmsg<span class="token operator">=</span><span class="token string">'菜单修改成功!'</span><span class="token punctuation">)</span>
    <span class="token keyword">else</span><span class="token punctuation">:</span>
        <span class="token keyword">return</span> render<span class="token punctuation">(</span>request<span class="token punctuation">,</span> <span class="token string">'admin/menu/update_menu.html'</span><span class="token punctuation">,</span> context<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">'form'</span><span class="token punctuation">:</span> form<span class="token punctuation">}</span><span class="token punctuation">)</span>

...

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

4>前端代码

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

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
4.2>js
// 这里的代码跟添加的js写法很相似,又是一个代码复用点
$(()=>{
    let $updateBtn = $('#modal-update button.update');
    let $form = $('#update-menu');
$updateBtn<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    $
        <span class="token punctuation">.</span><span class="token function">ajax</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
            url<span class="token punctuation">:</span> <span class="token string">'/admin/menu/'</span> <span class="token operator">+</span> menuId <span class="token operator">+</span> <span class="token string">'/'</span><span class="token punctuation">,</span>
            type<span class="token punctuation">:</span> <span class="token string">'PUT'</span><span class="token punctuation">,</span>
            data<span class="token punctuation">:</span> $form<span class="token punctuation">.</span><span class="token function">serialize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token comment">// dataType: "json"</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">done</span><span class="token punctuation">(</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span>errno <span class="token operator">===</span> <span class="token string">'0'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">// 关闭模态框</span>
                <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'#modal-update'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">modal</span><span class="token punctuation">(</span><span class="token string">'hide'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'hidden.bs.modal'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'#content'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>
                        <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'.sidebar-menu li.active a'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token string">'url'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                        <span class="token punctuation">(</span>response<span class="token punctuation">,</span> status<span class="token punctuation">,</span> xhr<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
                            <span class="token keyword">if</span> <span class="token punctuation">(</span>status <span class="token operator">!==</span> <span class="token string">'success'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                                message<span class="token punctuation">.</span><span class="token function">showError</span><span class="token punctuation">(</span><span class="token string">'服务器超时,请重试!'</span><span class="token punctuation">)</span>
                            <span class="token punctuation">}</span>
                        <span class="token punctuation">}</span>
                    <span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                message<span class="token punctuation">.</span><span class="token function">showSuccess</span><span class="token punctuation">(</span>res<span class="token punctuation">.</span>errmsg<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
                message<span class="token punctuation">.</span><span class="token function">showError</span><span class="token punctuation">(</span><span class="token string">'修改菜单失败!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 修改模态框的内容为, 后端返回的带有错误信息的表单</span>
                <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'#modal-update .modal-content'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">html</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">fail</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            message<span class="token punctuation">.</span><span class="token function">showError</span><span class="token punctuation">(</span><span class="token string">'服务器超时,请重试'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

});

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

VIII. 整合后台首页面菜单加载

我们来填之前菜单列表的坑, 之前我们使用list写的硬编码, 我们来到数据库中拿可用的菜单

1>后端代码

1.1>视图
class IndexView(LoginRequiredMixin, View):
    """
    后台首页视图
    """
<span class="token keyword">def</span> <span class="token function">get</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> request<span class="token punctuation">)</span><span class="token punctuation">:</span>
	
    objs <span class="token operator">=</span> models<span class="token punctuation">.</span>Menu<span class="token punctuation">.</span>objects<span class="token punctuation">.</span>only<span class="token punctuation">(</span><span class="token string">'name'</span><span class="token punctuation">,</span> <span class="token string">'url'</span><span class="token punctuation">,</span> <span class="token string">'icon'</span><span class="token punctuation">,</span> <span class="token string">'permission__codename'</span><span class="token punctuation">,</span>
                                    <span class="token string">'permission__content_type__app_label'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>select_related<span class="token punctuation">(</span>
        <span class="token string">'permission__content_type'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token builtin">filter</span><span class="token punctuation">(</span>is_delete<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">,</span> is_visible<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> parent<span class="token operator">=</span><span class="token boolean">None</span><span class="token punctuation">)</span>
    has_permissions <span class="token operator">=</span> request<span class="token punctuation">.</span>user<span class="token punctuation">.</span>get_all_permissions<span class="token punctuation">(</span><span class="token punctuation">)</span>
    menus <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
    <span class="token keyword">for</span> menu <span class="token keyword">in</span> objs<span class="token punctuation">:</span>
        <span class="token keyword">if</span> <span class="token string">'%s.%s'</span> <span class="token operator">%</span> <span class="token punctuation">(</span>menu<span class="token punctuation">.</span>permission<span class="token punctuation">.</span>content_type<span class="token punctuation">.</span>app_label<span class="token punctuation">,</span> menu<span class="token punctuation">.</span>permission<span class="token punctuation">.</span>codename<span class="token punctuation">)</span> <span class="token keyword">in</span> has_permissions<span class="token punctuation">:</span>
            temp <span class="token operator">=</span> <span class="token punctuation">{</span>
                <span class="token string">'name'</span><span class="token punctuation">:</span> menu<span class="token punctuation">.</span>name<span class="token punctuation">,</span>
                <span class="token string">'icon'</span><span class="token punctuation">:</span> menu<span class="token punctuation">.</span>icon
            <span class="token punctuation">}</span>

            children <span class="token operator">=</span> menu<span class="token punctuation">.</span>children<span class="token punctuation">.</span><span class="token builtin">filter</span><span class="token punctuation">(</span>is_delete<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">,</span> is_visible<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
            <span class="token keyword">if</span> children<span class="token punctuation">:</span>
                temp<span class="token punctuation">[</span><span class="token string">'children'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
                <span class="token keyword">for</span> child <span class="token keyword">in</span> children<span class="token punctuation">:</span>
                    <span class="token keyword">if</span> <span class="token string">'%s.%s'</span> <span class="token operator">%</span> <span class="token punctuation">(</span>child<span class="token punctuation">.</span>permission<span class="token punctuation">.</span>content_type<span class="token punctuation">.</span>app_label<span class="token punctuation">,</span> child<span class="token punctuation">.</span>permission<span class="token punctuation">.</span>codename<span class="token punctuation">)</span> <span class="token keyword">in</span> has_permissions<span class="token punctuation">:</span>
                        temp<span class="token punctuation">[</span><span class="token string">'children'</span><span class="token punctuation">]</span><span class="token punctuation">.</span>append<span class="token punctuation">(</span><span class="token punctuation">{</span>
                            <span class="token string">'name'</span><span class="token punctuation">:</span> child<span class="token punctuation">.</span>name<span class="token punctuation">,</span>
                            <span class="token string">'url'</span><span class="token punctuation">:</span> child<span class="token punctuation">.</span>url
                        <span class="token punctuation">}</span><span class="token punctuation">)</span>
            <span class="token keyword">else</span><span class="token punctuation">:</span>
                <span class="token keyword">if</span> <span class="token operator">not</span> menu<span class="token punctuation">.</span>url<span class="token punctuation">:</span>
                    <span class="token keyword">continue</span>
                temp<span class="token punctuation">[</span><span class="token string">'url'</span><span class="token punctuation">]</span> <span class="token operator">=</span> menu<span class="token punctuation">.</span>url
            menus<span class="token punctuation">.</span>append<span class="token punctuation">(</span>temp<span class="token punctuation">)</span>
    <span class="token keyword">print</span><span class="token punctuation">(</span>menus<span class="token punctuation">)</span>
 <span class="token keyword">return</span> render<span class="token punctuation">(</span>request<span class="token punctuation">,</span> <span class="token string">'admin/index.html'</span><span class="token punctuation">,</span> context<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">'menus'</span><span class="token punctuation">:</span> menus<span class="token punctuation">}</span><span class="token punctuation">)</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

再运行之前, 一定要先添加一个菜单管理, 这样才可以看到我们的菜单列表效果

但是有一个bug, 当我们添加了一个新菜单之后, 虽然可以展示出来, 但是点击访问时就会提示我们没有定义路由,

这个可以设计一个自定义标签, 使用异常处理的方式, 若使用的使错误的路由, 就展示wait界面, 代码如下:

# 在myadmin/templatetags/admin_customer_tags.py中添加如下过滤器
@register.simple_tag()
def my_url(pattern, *args):
    try:
        url = reverse(pattern, *args)
    except Exception as e:
        url = reverse('myadmin:wait')
    return url

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

然后在前端代码中引用:

<!-- 在templates/myadmin/index.html中修改如下代码 -->
            <!-- Sidebar Menu -->
            <ul class="sidebar-menu" data-widget="tree">
                {% for menu in menus %}
                    {% if 'children' in menu %}
                        <li class="treeview">
                            <a href="#"><i class="fa {{ menu.icon }}"></i> <span>{{ menu.name }}</span>
                                <span class="pull-right-container">
                                    <i class="fa fa-angle-left pull-right"></i>
                                </span>
                            </a>
                            <ul class="treeview-menu">
                                {% for child in menu.children %}
                                    <li>
                                        <a href="#" data-url="{% my_url child.url  %}"><!-- 使用my_url过滤器 -->
                                            {{ child.name }}
                                        </a>
                                    </li>
                                {% endfor %}
                            </ul>
                        </li>
                    {% else %}
                        <li><a href="#" data-url="{% my_url menu.url %}"><!-- 使用my_url过滤器 -->
                            <i class="fa {{ menu.icon }}"></i>
                            <span>{{ menu.name }}</span></a></li>
                    {% endif %}
                {% endfor %}
            </ul>

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
                                </div>
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-095d4a0b23.css" rel="stylesheet">
                </div>
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值