zoukankan      html  css  js  c++  java
  • 权限组件(8):一级菜单的展示、增删改查和保留原参数

    效果图:

    一、路由配置

    rbac/urls.py

    from django.urls import re_path
    from rbac.views import menu urlpatterns = [ ... # 菜单管理 re_path(r'^menu/list/$', menu.menu_list, name='menu_list'), re_path(r'^menu/add/$', menu.menu_add, name='menu_add'), re_path(r'^menu/edit/(?P<pk>d+)/$', menu.menu_edit, name='menu_edit'), re_path(r'^menu/del/(?P<pk>d+)/$', menu.menu_del, name='menu_del'), ... ]

    二、forms表单验证

    rbac/forms/menu.py

    from django import forms
    from django.utils.safestring import mark_safe
    
    from rbac import models
    
    ICON_LIST = [
        ['fa-hand-scissors-o', '<i aria-hidden="true" class="fa fa-hand-scissors-o"></i>'],
        ['fa-hand-spock-o', '<i aria-hidden="true" class="fa fa-hand-spock-o"></i>'],
        ['fa-hand-stop-o', '<i aria-hidden="true" class="fa fa-hand-stop-o"></i>'],
        ['fa-handshake-o', '<i aria-hidden="true" class="fa fa-handshake-o"></i>'],
        ['fa-hard-of-hearing', '<i aria-hidden="true" class="fa fa-hard-of-hearing"></i>'],
        ['fa-hashtag', '<i aria-hidden="true" class="fa fa-hashtag"></i>'],
        ['fa-hdd-o', '<i aria-hidden="true" class="fa fa-hdd-o"></i>'],
        ['fa-headphones', '<i aria-hidden="true" class="fa fa-headphones"></i>'],
        ['fa-heart', '<i aria-hidden="true" class="fa fa-heart"></i>'],
        ['fa-heart-o', '<i aria-hidden="true" class="fa fa-heart-o"></i>'],
        ['fa-heartbeat', '<i aria-hidden="true" class="fa fa-heartbeat"></i>'],
        ['fa-history', '<i aria-hidden="true" class="fa fa-history"></i>'],
        ['fa-home', '<i aria-hidden="true" class="fa fa-home"></i>'],
        ['fa-hotel', '<i aria-hidden="true" class="fa fa-hotel"></i>'],
        ['fa-hourglass', '<i aria-hidden="true" class="fa fa-hourglass"></i>'],
        ['fa-hourglass-1', '<i aria-hidden="true" class="fa fa-hourglass-1"></i>'],
        ['fa-hourglass-2', '<i aria-hidden="true" class="fa fa-hourglass-2"></i>'],
        ['fa-hourglass-3', '<i aria-hidden="true" class="fa fa-hourglass-3"></i>'],
        ['fa-hourglass-end', '<i aria-hidden="true" class="fa fa-hourglass-end"></i>'],
        ['fa-hourglass-half', '<i aria-hidden="true" class="fa fa-hourglass-half"></i>'],
        ['fa-hourglass-o', '<i aria-hidden="true" class="fa fa-hourglass-o"></i>'],
        ['fa-hourglass-start', '<i aria-hidden="true" class="fa fa-hourglass-start"></i>'],
        ['fa-i-cursor', '<i aria-hidden="true" class="fa fa-i-cursor"></i>'],
        ['fa-id-badge', '<i aria-hidden="true" class="fa fa-id-badge"></i>'],
        ['fa-id-card', '<i aria-hidden="true" class="fa fa-id-card"></i>'],
        ['fa-id-card-o', '<i aria-hidden="true" class="fa fa-id-card-o"></i>'],
        ['fa-image', '<i aria-hidden="true" class="fa fa-image"></i>'],
        ['fa-mail-reply-all', '<i aria-hidden="true" class="fa fa-mail-reply-all"></i>'],
        ['fa-reply', '<i aria-hidden="true" class="fa fa-reply"></i>'],
        ['fa-reply-all', '<i aria-hidden="true" class="fa fa-reply-all"></i>'],
        ['fa-retweet', '<i aria-hidden="true" class="fa fa-retweet"></i>'],
        ['fa-wrench', '<i aria-hidden="true" class="fa fa-wrench"></i>']]
    
    """
     mark_safe:
     Explicitly mark a string as safe for (HTML) output purposes. The returned
     object can be used everywhere a string is appropriate.
    """
    for item in ICON_LIST:
        item[1] = mark_safe(item[1])
    
    
    class MenuModelForm(forms.ModelForm):
        class Meta:
            model = models.Menu
            fields = ['title', 'icon']
    
            widgets = {
                'title': forms.TextInput(attrs={'class': 'form-control'}),
                'icon': forms.RadioSelect(
                    choices=ICON_LIST,
                    attrs={'class': 'clearfix'}
                )
            }

    三、视图函数

    from django.shortcuts import HttpResponse, render, redirect, reverse
    
    from rbac import models
    from rbac.forms.menu import MenuModelForm
    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')
    
        context = {
            'menu_list': menu_queryset,
            'menu_id': menu_id
        }
    
        return render(request, 'rbac/menu_list.html', context)
    
    
    def menu_add(request):
        """
         菜单和权限列表
        :param request:
        :return:
        """
        if request.method == 'GET':
            forms = MenuModelForm()
            return render(request, 'rbac/change.html', {'forms': forms})
    
        forms = MenuModelForm(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 menu_edit(request, pk):
        """
        编辑一级菜单
        :param request:
        :param pk:
        :return:
        """
        menu_obj = models.Menu.objects.filter(id=pk).first()
    
        if not menu_obj:
            return HttpResponse('菜单不存在')
    
        if request.method == 'GET':
            forms = MenuModelForm(instance=menu_obj)
            return render(request, 'rbac/change.html', {'forms': forms})
    
        forms = MenuModelForm(data=request.POST, instance=menu_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 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.Menu.objects.filter(id=pk).delete()
    
        return redirect(menu_list_url)
    
    

    memory_reverse的功能是当用户完成增删改返回列表页的时候,还带有原参数,这样回列表页的时候还会默认选中用户刚刚选中的参数

     

    四、保留原参数

    rbac/templatestags/rbac.py

    ...
    from django.template import Library
    
    from rbac.service import urls
    
    register = Library()
    
    @register.simple_tag()
    def memory_url(request, name, *args, **kwargs):
        """
        生成带有原搜索条件的URL(替代了模板中的url)
        :param request:
        :param name:
        :param args:
        :param kwargs:
        :return:
        """
        return urls.memory_url(request, name, *args, **kwargs)
    ...

    rbac/service/urls.py

    from django.http import QueryDict
    
    from django.shortcuts import reverse
    
    
    def memory_url(request, name, *args, **kwargs):
        # reverse用法:reverse('name', kwargs={'pk': 1})
        # reverse用法:reverse('name', args=(1,))
        basic_url = reverse(name, args=args, kwargs=kwargs)
        # 当前url中无参数
        if not request.GET:
            return basic_url
    
        old_params = request.GET.urlencode()  # 获取url中的参数
    
        query_dict = QueryDict(mutable=True)  # 提供转义功能
        query_dict['_filter'] = old_params
    
        # urlencode帮我们自动转义。
        # 如果不用urlencode,&符号会把这个参数分割成两个参数:_filter=mid=2 和 age=99
        return '%s?%s' % (basic_url, query_dict.urlencode())  # _filter=mid=2&age=99
    
    
    def memory_reverse(request, name, *args, **kwargs):
        """
        反向生成URL
            http://127.0.0.1:8000/rbac/menu/edit/1/?_filter=mid%3D4
            1. 在URL获取原来的搜索条件获取(filter后的值)
            2. reverse生成原来的URL,如:/menu/list/
            3. /menu/list/?mid%3D4
    
        :param request:
        :param name:
        :param args:
        :param kwargs:
        :return:
        """
    
        url = reverse(name, args=args, kwargs=kwargs)
        original_parmas = request.GET.get('_filter')
        if original_parmas:
            url = '%s?%s' % (url, original_parmas)
        return url

    由于需要传的参数超过了两个,所以需要用simple_tag。memory_url在模板用的。memory_reverse是在视图函数中反向解析的时候用的。

     

    五、模板

    模板层新增了菜单列表的模板,增、改页面由于新增了许多图标,所以也有一些小的变动。
    rbac/templates/rbac/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>
    
    {% endblock content %}

    需要用模板语法判断用户选中的菜单并给其一个active的样式

    rbac/templates/rbac/change.html

    {% extends 'layout.html' %}
    
    {% block css %}
        <style>
            ul {
                list-style-type: none;
                padding: 0;
            }
    
            ul li {
                float: left;
                padding: 10px;
                padding-left: 0;
                width: 80px;
            }
    
            ul li i {
                font-size: 18px;
                margin-left: 5px;
                color: #6d6565;
            }
        </style>
    {% endblock css %}
    
    {% block content %}
    
        <div class="luffy-container">
            <form class="form-horizontal" action="" method="post" novalidate>
                {% csrf_token %}
                {% for field in forms %}
                    <div class="form-group">
                        <label class="col-sm-2 control-label" for="{{ field.auto_id }}">{{ field.label }}</label>
                        <div class="col-sm-8">
                            {{ field }}
                            <span style="color:red;">{{ field.errors.0 }}</span>
                        </div>
                    </div>
                {% endfor %}
                <div class="form-group">
                    <div class="col-sm-offset-2 col-sm-8">
                        <input type="submit" value="提交" class="btn btn-primary">
                    </div>
                </div>
            </form>
        </div>
    
    {% endblock content %}
  • 相关阅读:
    开发记录4
    开发记录3
    豆瓣的基础架构读后感
    开发记录2
    开发记录1
    大数据技术大作业1
    新浪微博平台架构读后感
    第一阶段冲刺第五天
    第一阶段冲刺第四天
    第一阶段冲刺第三天
  • 原文地址:https://www.cnblogs.com/lshedward/p/10505622.html
Copyright © 2011-2022 走看看