后台菜单管理功能
菜单的管理功能其实就是, 对菜单的增删改查
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>业务流程分析
- 获取未删除,的一级菜单
- 根据一级菜单获取未删除的二级菜单
- 渲染页面
2>接口设计
- 接口说明
类目 | 说明 |
---|---|
请求方法 | GET |
url定义 | /admin/menus/ |
参数格式 | 无参数 |
-
返回结果
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的服务哦
页面效果:
可以打开这个界面, 就说明路由和视图配置好了
接下来将列表填充到这个页面, 我们可以使用AdminLTE
为用户提供的表格模板:
这个页面上有很多类型的表格, 修改前端代码
{% 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>接口设计
- 接口说明:
类目 | 说明 |
---|---|
请求方法 | GET |
url定义 | /admin/menu/ |
参数格式 | 无参数 |
-
返回数据
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"><!-- add modle --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token comment"><!-- /.modal-content --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token comment"><!-- /.modal-dialog --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token comment"><!-- /.modal --></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">×</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"><</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">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span>{{ field }}{{ field.label }}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> {% else %} <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span>{{ field.label }}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span> {% for error in field.errors %} <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span>{{ error }}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> {% endfor %} {% add_class field 'form-control' %} <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> {% endif %} {% endfor %} <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>form</span><span class="token punctuation">></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
页面效果:
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">=></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">=></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">=></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">×</span></button>
<h4 class="modal-title">警告</h4>
</div>
<div class="modal-body">
<p>One fine body…</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">=></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">=></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">=></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">&&</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>接口设计
- 接口说明:
类目 | 说明 |
---|---|
请求方法 | GET |
url定义 | /admin/menu/<int:menu_id>/ |
参数格式 | 路径参数 |
- 参数说明
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
menu_id | 整数 | 是 | 菜单id |
-
返回数据
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"></</span>div</span><span class="token punctuation">></span></span> <span class="token comment"><!-- /.modal-content --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token comment"><!-- /.modal-dialog --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token comment"><!-- /.modal --></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">×</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"><</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">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span>{{ field }}{{ field.label }}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> {% else %} <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span>{{ field.label }}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span> {% for error in field.errors %} <span class="token tag"><span class="token tag"><span class="token punctuation"><</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">></span></span>{{ error }}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> {% endfor %} {% add_class field 'form-control' %} <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> {% endif %} {% endfor %} <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>form</span><span class="token punctuation">></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">=></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">=></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">=></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>接口设计
- 接口说明:
类目 | 说明 |
---|---|
请求方法 | PUT |
url定义 | /admin/menu/<int:menu_id> |
参数格式 | 路径参数+表单参数 |
- 参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
menu_id | 整数 | 是 | 菜单id |
name | 字符串 | 是 | 菜单名 |
url | 字符串 | 否 | 当前文章页数 |
order | 整数 | 是 | 排序 |
parent | 整数 | 否 | 父菜单id |
icon | 字符串 | 是 | 渲染图标类名 |
codename | 字符串 | 是 | 权限码 |
is_visible | 整数 | 是 | 是否可见 |
-
返回数据
# 添加正常返回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">=></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">=></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">=></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>