权限组件(9):二级菜单的展示和增删改查

效果图:

二级菜单的展示和增删改查

二级菜单和一级菜单逻辑差不太多。有以下两点需要注意:

  1. 用户不点一级菜单的时候,二级菜单的信息、新建、编辑、删除不会显示
  2. 新建二级菜单的时候,默认选中当前用户选中的一级菜单
  3. 数据库把icon字段的null、blank=True去掉 (需要给已有数据一个默认值)

 

一、配置URL

rbac/urls.py

...
from django.urls import re_path

from rbac.views import menu
...

urlpatterns = [
    ...
    # 二级菜单
    re_path(r'^second/menu/add/(?P<menu_id>d+)/$', menu.second_menu_add, name='second_menu_add'),
    re_path(r'^second/menu/edit/(?P<pk>d+)/$', menu.second_menu_edit, name='second_menu_edit'),
    re_path(r'^second/menu/del/(?P<pk>d+)/$', menu.second_menu_del, name='second_menu_del'),
    ...
]

增加二级菜单需要默认选中一级菜单,所以需要一级菜单的id(在模板层会传入)。

二、forms表单验证

forms/base.py

from django import forms


class BaseBootStrapForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'

forms/menu.py

...
from rbac import models
from rbac.forms.base import BaseBootStrapForm
...

class SecondMenuModelForm(BaseBootStrapForm):
    class Meta:
        model = models.Permission
        exclude = ['pid'

三、视图函数

rbac/veiws/menu.py

from django.shortcuts import HttpResponse, render, redirect, reverse

from rbac import models
from rbac.forms.menu import MenuModelForm, SecondMenuModelForm
from rbac.service.urls import memory_reverse


def menu_list(request):
    """
    菜单和权限列表
    :param request:
    :return:
    """
    menu_queryset = models.Menu.objects.all()

    menu_id = request.GET.get('mid')  # 用户选择的一级菜单

    second_menu_id = request.GET.get('sid')  # 用户选择的二级菜单  +

    menus_exists = models.Menu.objects.filter(id=menu_id).exists()

    if not menus_exists:
        menu_id = None

    if menu_id:
        second_menus = models.Permission.objects.filter(menu_id=menu_id)
    else:
        second_menus = []

    context = {
        'menu_list': menu_queryset,
        'menu_id': menu_id,
        'second_menus': second_menus,
        'second_menu_id': second_menu_id
    }

    return render(request, 'rbac/menu_list.html', context)

...
# 二级菜单的增删改 def second_menu_add(request, menu_id): """ 增加二级菜单 :param request: :param pk: 已经选择的一级菜单ID(用于设置默认值) :return: """ menu_obj = models.Menu.objects.filter(id=menu_id).first() if request.method == 'GET': forms = SecondMenuModelForm(initial={'menu': menu_obj}) return render(request, 'rbac/change.html', {'forms': forms}) forms = SecondMenuModelForm(data=request.POST) if forms.is_valid(): forms.save() url = memory_reverse(request, 'rbac:menu_list') return redirect(url) return render(request, 'rbac/change.html', {'forms': forms}) def second_menu_edit(request, pk): """ 编辑二级菜单 :param request: :param pk: :return: """ permission_obj = models.Permission.objects.filter(id=pk).first() if request.method == 'GET': forms = SecondMenuModelForm(instance=permission_obj) return render(request, 'rbac/change.html', {'forms': forms}) forms = SecondMenuModelForm(data=request.POST, instance=permission_obj) if forms.is_valid(): forms.save() url = memory_reverse(request, 'rbac:menu_list') return redirect(url) return render(request, 'rbac/change.html', {'forms': forms}) def second_menu_del(request, pk): """ 删除二级菜单 :param request: :param pk: :return: """ menu_list_url = memory_reverse(request, 'rbac:menu_list') if request.method == 'GET': return render(request, 'rbac/delete.html', {'cancel': menu_list_url}) models.Permission.objects.filter(id=pk).delete() return redirect(menu_list_url)

 

四、模板渲染

rbac/templates/menu_list.html

{% extends 'layout.html' %}
{% load rbac %}

<style>
    tr.active {
        border-left: 3px solid #fdc00f;
    }
</style>

{% block content %}
    <div class="luffy-container">
        <!-- 一级菜单 -->
        <div class="col-md-3">
            <div class="panel panel-default">
                <!-- Default panel contents -->
                <div class="panel-heading">
                    <i class="fa fa-book" aria-hidden="true">一级菜单</i>
                    <a href="{% memory_url request 'rbac:menu_add' %}" class="right btn btn-success btn-xs"
                       style="padding: 2px 8px;margin:-3px">
                        <i class="fa fa-plus-circle" aria-hidden="true">新建</i>
                    </a>
                </div>
                <!-- Table -->
                <table class="table">
                    <thead>
                    <tr>
                        <th>名称</th>
                        <th>图标</th>
                        <th>选项</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for menu in menu_list %}
                        <!-- 管道符可以将后端传来的整型,转换成字符串 -->
                        <tr class="{% if menu.id|safe == menu_id %}active{% endif %}">
                            <td><a href="?mid={{ menu.id }}">{{ menu.title }}</a></td>
                            <td><i class="fa {{ menu.icon }}" aria-hidden="true"></i></td>
                            <td>
                                <a style="color: #333333; font-size:18px"
                                   href="{% memory_url request 'rbac:menu_edit' pk=menu.id %}">
                                    <i class="fa fa-edit" aria-hidden="true"></i>
                                </a>

                                <a style="color: red; font-size:18px"
                                   href="{% memory_url request 'rbac:menu_del' pk=menu.id %}">
                                    <i class="fa fa-trash-o" aria-hidden="true"></i>
                                </a>
                            </td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>


        <!-- 二级菜单 -->
        <div class="col-md-4">
            <div class="panel panel-default">
                <!-- Default panel contents -->
                <div class="panel-heading">
                    <i class="fa fa-flag" aria-hidden="true">二级菜单</i>
                    {% if menu_id %}
                        <a href="{% memory_url request 'rbac:second_menu_add' menu_id=menu_id %}"
                           class="right btn btn-success btn-xs"
                           style="padding: 2px 8px;margin:-3px">
                            <i class="fa fa-plus-circle" aria-hidden="true">新建</i>
                        </a>
                    {% endif %}
                </div>

                <!-- Table -->
                <table class="table">
                    <thead>
                    <tr>
                        <td>名称</td>
                        <td>CODE&URL</td>
                        <td>选项</td>
                    </tr>
                    </thead>

                    <tbody>
                    {% for second_menu in second_menus %}
                        <!-- 管道符可以将后端传来的整型,转换成字符串 -->
                        <tr class="{% if second_menu.id|safe == second_menu_id %}active{% endif %}">
                            <td rowspan="2">
                                <a href="?mid={{ menu_id }}&sid={{ second_menu.id }}">{{ second_menu.title }}</a>
                            </td>
                            <td>{{ second_menu.name }}</td>

                            <td>
                                <a href="{% memory_url request 'rbac:second_menu_edit' pk=second_menu.id %}"
                                   style="color:#333333;font-size:18px;">
                                    <i class="fa fa-edit" aria-hidden="true"></i>
                                </a>

                                <a href="{% memory_url request 'rbac:second_menu_del' pk=second_menu.id %}"
                                   style="color:red;font-size:18px;">
                                    <i class="fa fa-trash-o" aria-hidden="true"></i>
                                </a>
                            </td>
                        </tr>


                        <tr class="{% if second_menu.id|safe == second_menu_id %}active{% endif %}">
                            <td colspan="2" style="border-top:0;">{{ second_menu.url }}</td>
                        </tr>

                    {% endfor %}

                    </tbody>
                </table>
            </div>
        </div>
    </div>
{% endblock content %}

在总结一下django处理url的流程:在模板层通过反向解析找到url,并把模板层传递的参数传过去,然后到路由层,把request和模板层传过来的参数交给视图函数。

原文地址:https://www.cnblogs.com/lshedward/p/10506293.html