单爆手

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
内容回顾
    1. 二级菜单
        1. 建立个Menu的表,专门用来存一级菜单
        2. 权限通过外键和Menu关联,权限通过show字段来控制是否显示成单独的二级菜单
        3. jQuery绑定点击事件(左侧菜单的示例)
        4. 给Menu菜单分配权重,实现自定义菜单的显示顺序
        5. 二级菜单默认选中,其一级菜单默认展开
    2. 面包屑导航
        中国/广东/深圳/南山区
        [目录, 一级菜单, 二级菜单,三级菜单]
        目录: {
            一级菜单: {
                二级菜单:{
                    三级菜单: {
                        'pid' : 3,
                        'title': '三级菜单',
                        'url: '/xx/'
                    }
                }
            }
        }
        1. request.bread_crumb = []  --> 每次请求来都生成一个自己的面包屑导航
    3. 权限粒度细分到按钮
        1. request.session['permission_list'] = ['customer/edit/(?P<cid>\d+)/', ...]
        2. request.session['permission_list'] = [{'url': 'customer/edit/(?P<cid>\d+)/', ...]
        3. request.session['permission_dict'] = {
                    'web:customer_edit': {'url': 'customer/edit/(?P<cid>\d+)/', 'menu_id': 1}
                }
        4. 自定义filter实现是否显示的判断
            {{ request|has_permission:'web:customer_edit'  }}
2. 今日内容
    1. CRM一样的操作再来三遍
        1. 角色
        2. 菜单
        3. 权限
    2. 把icon爬下来让用户直接选
        1. 安装requests:http://cn.python-requests.org/zh_CN/latest/
            pip install requests
        2. 安装beautifulsoup4:https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/
            pip install beautifulsoup4
        3. MenuForm重写icon字段为单选框,将选项设置为上面爬取得图标列表

一.角色增删改查

1.角色页面展示创建

   需求实现如下图效果:其实它就是一个查询角色表,用一个table显示出来。

   先在settings中把权限校验的中间件注释掉#'rbac.midd.......',此时它会提示request对象没有request.bread_crumb属性。(因为此前是在中间件中对它做了赋值,注释后面再取就取不到),且layout.html中也注释掉

{#            {% load rbac %}#}
{# {% show_menu request %}#}
{#           {% bread_crumb request %}#}

(1)rbac/urls.py中:

app_name = '[rbac]'
url('^role/$',views.role_list, name='role_list'),

(2)luffy_permission/urls.py中导入二级路由把rbac开头的都跑到rbac的url中:

url(r'^rbac', include('rbac.urls', namespace='rbac')),

(3)rbac/views.py:

def role_list(request):
queryset = Role.objects.all() #查询数据库中所有角色的权限信息
return render(request, 'rbac/role_list.html', {'role_list': queryset})

(4)rbac/templates/rbac/role_list.html:

  导入layout.html布局模版。并替换它content的block块。并在其中写一表格--加边框加条形状(外边套一div标签).tbody中有一个权限就生成一个tr(序号,名称,数量,操作---models.py中由角色查到它的权限是点permissions拿到的是manytomany,所以所有权限应该是permissions.all,点all得到的是一queryset,所以点count就能得到数量。操作中有一编辑是a标签btn,且btn超小,有图标i标签表示.还有一删除操作),

<td>
<a href=""><i class="fa fa-pencil"></i></a>
<a href=""><i class="fa fa-trash-o"></i></a>
</td>

登录后输入如下url就出现如下角色的基本页面效果了:

 

2.在上述效果中实现完整的增删改查角色页面--编辑和添加:

 (1)rbac/urls.py中:添加和编辑用一个视图

app_name = '[rbac]'
urlpatterns = [
    url('^role/$',views.role_list, name='role_list'),
    url('^role_add/$',views.op_role, name='role_add'),
    url('^role_edit(\d+)/$',views.op_role, name='role_edit'),
    url('^role_del/(\d+)$',views.role_del, name='role_del'),
]

(2)rbac/views.py中:

添加和编辑二合一视图,添加和编辑页面op_role.html页面返回一form表单让他去填--用form,

from rbac.forms import RoleForm, MenuForm, PermissionForm
# 添加和编辑
def op_role(request, edit_id=None):
    edit_obj = Role.objects.filter(pk=edit_id).first()
    form_obj = RoleForm(instance=edit_obj)
    if request.method == 'POST': #一点提交
        form_obj = RoleForm(request.POST, instance=edit_obj)
        if form_obj.is_valid():
            form_obj.save()
            return redirect(reverse('rbac:role_list'))
    return render(request, 'rbac/op_role.html', {'form_obj': form_obj})


# 删除
def role_del(request, del_id):
    Role.objects.filter(pk=del_id).delete()
    return redirect(reverse('rbac:role_list'))

(3)rbac/templates/rbac/role_list.html: 

{% extends 'layout.html' %}
{% block content %}
    <div>
        <a class="btn btn-success" href="{% url 'rbac:role_add' %}"><i class="fa fa-plus-circle"></i>添加</a>
        <table class="table table-bordered table-striped">
            <thead>
            <tr>
                <th>#</th>
                <th>角色名称</th>
                <th>权限数量</th>
                <th>操作</th>
            </tr>
            </thead>
            <tbody>
            {% for role in role_list %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>{{ role.title }}</td>
                    <td>{{ role.permissions.count }}</td>
                    <td>
                        <a  href="{% url 'rbac:role_edit' role.id %}"><i class="fa fa-pencil"></i></a>
                        <a  href="{% url 'rbac:role_del' role.id %}"><i class="fa fa-trash-o"></i></a>
                    </td>
                </tr>
            {% endfor %}

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

(5)rbac/forms.py中:

from rbac.models import Role, Menu, Permission
# Role的Model Form
class RoleForm(forms.ModelForm):
    class Meta:
        model = Role
        fields = '__all__'
    #自定样式
    def __init__(self, *args, **kwargs):
        super(RoleForm, self).__init__(*args, **kwargs)
        for field in self.fields.values():
#self.fields是ordedendict有序的字典,values是form表单中每一个字段对象
            field.widget.attrs.update({'class': 'form-control'})

(6)rbac/templates/rbac/op_role.html:

  div标签中写一form表单,循环,有一个字段就生成一个label标签,

{% extends 'layout.html' %}
{% block content %}
    <div class="container">
    <h2>添加角色</h2>
        <form action="" method="post">
            {% csrf_token %}
            {% for field in form_obj %}
                <div class="form-group">
                    <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                    {{ field }} {#会自动生成input标签#}
                    <span class="help-block">{{ field.errors.0 }}</span>
                </div>
            {% endfor %}
            <div class="form-group">
                <button type="submit" class="btn btn-success">提交</button>
            </div>

        </form>
    </div>
{% endblock %}

最后就实现如下效果了:

二.菜单和权限的展示

   需求:功能一:想实现如下效果:菜单和权限放一起了一个列表里,访问rbac/menu_list/左边显示菜单右边显示权限。功能二:且点击客户管理时,在右侧显示只显示客户管理菜单的所有权限--a标签(a标签上显示当前url并后面跟一?menu_id=,那查权限时不是查询所有的权限,而是根据这个id查权限)。点击帐单管理,右侧只显示帐单管理的所有权限。功能三:且点中它时显示高亮,把此行tr的背景色换下就可--当前url中的menu_id值和当前选中行的id一样则给高亮显示--<tr {% if request|is_this_menu:menu.id %} class="bg-success"{% endif %}>。---注意对象点id得到是一数字,而request参数里带的永远都是字符串,所以我在rbac/templatetags/rbac.py中自定义filter。

(1)rbac/urls.py:

app_name = '[rbac]'
urlpatterns = [
    # 角色管理
    url(r'^role_list/$', views.role_list, name='role_list'),
    url(r'^role_add/$', views.op_role, name='role_add'),
    url(r'^role_edit/(\d+)/$', views.op_role, name='role_edit'),
    url(r'^role_del/(\d+)/$', views.role_del, name='role_del'),
    # 菜单管理
    url(r'^menu_list/$', views.menu_list, name='menu_list'),
    url(r'^menu_add/$', views.op_menu, name='menu_add'),
    url(r'^menu_edit/(\d+)/$', views.op_menu, name='menu_edit'),
    url(r'^menu_del/(\d+)/$', views.menu_del, name='menu_del'),
    # 权限管理
    url(r'^permission_add/$', views.op_permission, name='permission_add'),
    url(r'^permission_edit/(\d+)/$', views.op_permission, name='permission_edit'),
    url(r'^permission_del/(\d+)/$', views.permission_del, name='permission_del'),
]

 (2)rbac/views.py

  菜单列表视图中,把所有的菜单和权限拿出来--查两份表。

  做判断,有无menu_id

# 菜单列表
def menu_list(request):
    # 先查询出所有的菜单
    menu_queryset = Menu.objects.all()
    menu_id = request.GET.get('menu_id')
    if menu_id:
        # 表示根据菜单去查询它对应的权限
        permission_queryset = Permission.objects.filter(menu_id=menu_id)
    else:
        # 查询所有的权限
        permission_queryset = Permission.objects.all()
    return render(request, 'rbac/menu_list.html', {'menu_list': menu_queryset, 'permission_list': permission_queryset})
def op_menu(request, edit_id=None):
    pass
def menu_del(request, del_id):
    pass
def op_permission(request, edit_id=None):
    pass
def permission_del(request, del_id):
    pass

 (3)rbac/templates/rbac/menu_list.html

  面板,左边占4--col-me-4右边占8---col-me-8。栅格系统。样式为淡蓝色--panel-info

for循环menu_list,生成一个个具体的菜单,路由反向解析--url 'rbac:menu_edit' menu.id。

  循环权限permission_list。给菜单标题加一a标签--<a href="{% url 'rbac:menu_list' %}?menu_id={{ menu.id }}">。

{% extends 'layout.html' %}

{% block content %}

    <div class="container-fluid">
    <h2>菜单和权限管理</h2>
        <div class="row">
            <div class="col-md-4">
                <div class="panel panel-info">
                    <div class="panel-heading">
                        <h3 class="panel-title"><i class="fa fa-book"></i> 菜单管理
                            <a class="pull-right" href="{% url 'rbac:menu_add' %}"><i class="fa fa-plus-circle"></i></a>
                        </h3>
                    </div>
                    <div class="panel-body">
                        <table class="table table-bordered">
                            <thead>
                            <tr>
                                <th>#</th>
                                <th>菜单名称</th>
                                <th>图标</th>
                                <th>权重</th>
                                <th>操作</th>
                            </tr>
                            </thead>
                            <tbody>
                            {% for menu in menu_list %}
                                {% load rbac %}
                                <tr {% if request|is_this_menu:menu.id %} class="bg-success"{% endif %}>
                                <td>{{ forloop.counter }}</td>
                                <td><a href="{% url 'rbac:menu_list' %}?menu_id={{ menu.id }}">{{ menu.title }}</a></td>
                                <td><i class="fa {{ menu.icon }}"></i></td>
                                <td>{{ menu.weight }}</td>
                                <td>
                                    <a href="{% url 'rbac:menu_edit' menu.id %}"><i class="fa fa-pencil"></i></a>
                                    |
                                    <a href="{% url 'rbac:menu_del' menu.id %}"><i class="fa fa-trash-o"></i></a>
                                </td>
                                </tr>
                            {% endfor %}

                            </tbody>
                        </table>
                                        </div>
                </div>
            </div>
            <div class="col-md-8">
                <div class="panel panel-info">
                    <div class="panel-heading">
                        <h3 class="panel-title"><i class="fa fa-group"></i> 权限管理
                            <a class="pull-right" href="{% url 'rbac:permission_add' %}"><i class="fa fa-plus-circle"></i></a>
                        </h3>
                    </div>
                    <div class="panel-body">
                        <table class="table table-bordered table-striped">
                            <thead>
                            <tr>
                                <th>#</th>
                                <th>权限名称</th>
                                <th>URL</th>
                                <th>路由别名</th>
                                <th>是否显示</th>
                                <th>所属菜单</th>
                                <th>操作</th>
                            </tr>
                            </thead>
                            <tbody>
                            {% for permission in permission_list %}
                                <tr>
                                <td>{{ forloop.counter }}</td>
                                <td>{{ permission.title }}</td>
                                <td>{{ permission.url }}</td>
                                <td>{{ permission.name }}</td>
                                <td>{{ permission.show }}</td>
                                <td>{{ permission.menu.title }}</td>
                                <td>
                                    <a href="{% url 'rbac:permission_edit' permission.id %}"><i class="fa fa-pencil"></i></a>
                                    |
                                    <a href="{% url 'rbac:permission_del' permission.id %}"><i class="fa fa-trash-o"></i></a>
                                </td>
                                </tr>
                            {% endfor %}

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

(4)rbac/templatetags/rbac.py:自定义判断菜单的高亮显示

# 判断菜单的高亮显示
@register.filter() #给它注册一下
def is_this_menu(request, menu_id):
    m_id = request.GET.get('menu_id', 0)
    return str(m_id) == str(menu_id)

 

 三.菜单图标选项

  http://www.fontawesome.com.cn/---图标库 

  功能一:上述效果中的菜单管理和权限管理加图标。<i class="fa fa-book"></i> 菜单管理。<i class="fa fa-group"></i> 权限管理。功能二:在每一个菜单下面加添加按钮并且往右加a标签<a class="pull-right" href="{% url 'rbac:permission_add' %}"><i class="fa fa-plus-circle">。

  功能三:点添加图标就添加对应菜单和对应权限。功能四:在添加菜单时它的图标可以把bootstrap中所有图标拿过来显示在添加菜单页面,这样我直接手动勾选想要的图标即可--新建一爬虫脚本。所以如下图效果中是把icon这一列(input框)变成一选项选起来就行--forms.py的MenuForm中改即可。

(1)rbac/views.py中:

  op_menu视图中,返回op_menu.html页面--所以需要form表单。

def op_menu(request, edit_id=None):
    edit_obj = Menu.objects.filter(pk=edit_id).first()
    form_obj = MenuForm(instance=edit_obj)
    if request.method == 'POST':
        form_obj = MenuForm(request.POST, instance=edit_obj)
        if form_obj.is_valid():
            form_obj.save()
            return redirect(reverse('rbac:menu_list'))

    return render(request, 'rbac/op_menu.html', {'form_obj': form_obj, 'edit_id': edit_id})


def menu_del(request, del_id):
    Menu.objects.filter(pk=del_id).delete()
    return redirect(reverse('rbac:menu_list'))


def op_permission(request, edit_id=None):
    edit_obj = Permission.objects.filter(pk=edit_id).first()
    form_obj = PermissionForm(instance=edit_obj)
    if request.method == 'POST':
        form_obj = PermissionForm(request.POST, instance=edit_obj)
        if form_obj.is_valid():
            form_obj.save()
            return redirect(reverse('rbac:menu_list'))

    return render(request, 'rbac/op_permission.html', {'form_obj': form_obj, 'edit_id': edit_id})


def permission_del(request, del_id):
    Permission.objects.filter(pk=del_id).delete()
    return redirect(reverse('rbac:menu_list'))

 (2)rbac/forms.py中:

from django.utils.safestring import mark_safe
# Menu的Model Form
class MenuForm(forms.ModelForm):
    class Meta:
        model = Menu
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        super(MenuForm, self).__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs.update({'class': 'form-control'})
        # 把icon图标这个字段由input框变成单选框
        self.fields['icon'] = forms.ChoiceField(
            widget=forms.widgets.RadioSelect,
            choices=((i[0], mark_safe(i[1])) for i in ICON_CHOICES)
        )

(3)rbac/templates/rbac/op_menu.html

 判断有没有传入一edit_id。

{% extends 'layout.html' %}

{% block content %}

    <div class="container">
    <h2>{% if edit_id %}编辑菜单{% else %}添加菜单{% endif %}</h2>
        <form action="" method="post">
            {% csrf_token %}
            {% for field in form_obj %}
                <div class="form-group clearfix">
                    <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                    {{ field }}
                    <span class="help-block">{{ field.errors.0 }}</span>
                </div>
            {% endfor %}

            <div class="form-group">
                <button type="submit" class="btn btn-success">提交</button>
            </div>

        </form>
    </div>
{% endblock %}

 (4)rbac/templates/rbac/op_permissio.html

{% extends 'layout.html' %}

{% block content %}

    <div class="container">
    <h2>{% if edit_id %}编辑权限信息{% else %}添加权限信息{% endif %}</h2>
        <form action="" method="post">
            {% csrf_token %}
            {% for field in form_obj %}
                <div class="form-group">
                    <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                    {{ field }}
                    <span class="help-block">{{ field.errors.0 }}</span>
                </div>
            {% endfor %}

            <div class="form-group">
                <button type="submit" class="btn btn-success">提交</button>
            </div>

        </form>
    </div>
{% endblock %}

(5)luffy_permission/icon爬虫.py:  pip install requests -i https://pypi.douban.com/simple/   

pip install BeautifulSoup4 -i https://pypi.douban.com/simple/

此文件模块就是拿到所有icon图标的列表icon_list,列表里有小列表:图标的文本内容(样式名),i标签,如下

    [['fa-address-book', '<i aria-hidden="true" class="fa fa-address-book"></i>'],......]]

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django.utils.safestring import mark_safe
import requests
from bs4 import BeautifulSoup

# 使用requests模块发送get请求去访问如下url,拿到一响应对象并用utf-8编码
response = requests.get(
    url='http://fontawesome.dashgame.com/',
)
response.encoding = 'utf-8'
# 使用BS4模块去解析获取的网页内容--response.text是它会把你当前拿过来网页的text文本用一大的字符串,去用指定的beautifulsoup模块做一下解析,生成一beautifulsoup对象
#find是查找页面上所有带id属性web-application的标签并赋值给web对象,
soup = BeautifulSoup(response.text, 'html.parser')
web = soup.find(attrs={'id': 'web-application'})

icon_list = []
#在web里按照class属性是fa-hover去查找,然后把其中的i标签拿出来,并把它的class name拿出来,放到列表中。
for item in web.find_all(attrs={'class': 'fa-hover'}):
    tag = item.find('i')
    class_name = tag.get('class')[1]
    icon_list.append([class_name, str(tag)])

print(icon_list)
posted on 2020-04-27 08:19  单爆手  阅读(699)  评论(0)    收藏  举报