zoukankan      html  css  js  c++  java
  • 权限组件

    一. 把自己写的对权限的处理变成一个可以随时调用的组件(步骤)

    1.在项目中创建一个app

    命令:startapp rbac

    2.在rbac app下创建一个文件夹,service,将对权限处理的内容放到该文件夹下

    (1) 为该组件做数据库准备

    models.py:

    from django.db import models
    
    class User(models.Model):
        name=models.CharField(max_length=32)
        pwd=models.CharField(max_length=32)
        roles=models.ManyToManyField(to="Role")
        def __str__(self):
            return self.name
    
    
    class Role(models.Model):
        title=models.CharField(max_length=32)
        permissions=models.ManyToManyField(to="Permission")
        def __str__(self):
            return self.title
    
    class Permission(models.Model):
        title=models.CharField(max_length=32)
        url=models.CharField(max_length=32)
        def __str__(self):
            return self.title

    (2)为便于利用admin组件

    admin.py:

    from django.contrib import admin
    from rbac.models import *
    admin.site.register(User)
    admin.site.register(Role)
    class PermissionConfig(admin.ModelAdmin):
        list_display=["pk","title","url"]
        ordering = ["-pk"]
    admin.site.register(Permission,PermissionConfig)

    (3)service文件夹下创建middleware.py

    import re
    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse,redirect
    class SessionMiddleware(MiddlewareMixin):
        def process_request(self, request):
            path=request.path
            permission=request.session.get("permission")
            # 白名单
            for reg in ["/login/","/admin/*"]:
                ret=re.search(reg,path)
                if ret:
                    return None
            # 判断是否登录
            user_id=request.session.get("user_id")
            if not user_id:
                return redirect("/login/")
            # 校验权限
            for reg in permission:
                reg="^%s$" % reg
                ret=re.search(reg,path)
                if ret:
                    return None
            return HttpResponse("无权访问")

    (4)service文件夹下创建rbac.py

    from rbac.models import *
    def initial_sesson(request,user):
        permissions__url=Role.objects.filter(user__name=user).values("permissions__url")
        print(permissions__url)
        permissions__url_list=[]
        for item in permissions__url:
            print(item["permissions__url"])
            permissions__url_list.append(item["permissions__url"])
        print(type(permissions__url_list),permissions__url_list)
        request.session["permission"]=permissions__url_list

    3.Settings中也要相应修改路径

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'rbac.service.middleware.SessionMiddleware',
    ]
    
    同时值得注意的是,settings中的INSTALLED_APPS,也要添加rbac
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01.apps.App01Config',
        'rbac',
        'web',
    ]
    1. 以后处理权限问题时,只需要调用inital_session即可
    from django.shortcuts import render,HttpResponse
    from rbac.models import *
    from rbac.service.rbac import initial_sesson #引入
    def login(request):
        if request.method=="GET":
            return render(request,"web/login.html")
        else:
            user=request.POST.get("user")
            pwd=request.POST.get("pwd")
            use=User.objects.filter(name=user,pwd=pwd).first()
            if use:
                request.session["user_id"]=use.pk
                initial_sesson(request,user)  #调用
                return HttpResponse("登录成功")
            else:
                return HttpResponse("用户名或密码错误")

    二. 如何动态显示菜单权限

    1.问题关键:

    (1)由于角色的不同,所拥有的权限不同,左侧菜单列不同

    (2)在所有的权限中,并不是全都要显示在左侧菜单列,要根据情况有一定的筛选

    本次目的:增删该查,只有查作为左侧菜单显示

    2.解决方案:

    (1) permission表中新添加两个字段is_menu icon

    class Permission(models.Model):
        title=models.CharField(max_length=32)
        url=models.CharField(max_length=32)
        is_menu=models.BooleanField(default=False)
        icon=models.CharField(max_length=64,default="",blank=True,null=True)
        def __str__(self):
            return self.title

    (2) admin.py中配置让这两个字段显示

    class PermissionConfig(admin.ModelAdmin):
        list_display=["pk","title","url","is_menu","icon"]
        list_editable = ["url","icon"]  #注意问题:list_editable中的元素必须是list_display=中的元素
        search_fields = ["title"]
    admin.site.register(Permission,PermissionConfig)

    (3) rbac.py:

    is_nemutrue,title,icon,url三项都注入到session;is_nemufalse,只有url注入到session

    from rbac.models import Role
    def initial_sesson(request,user):
        """
        功能:将当前登录人的所有权限录入session中
        :param user: 当前登录人
        """
        # 查询当前登录人的所有权限列表
        # 查看当前登录人的所有角色
        # ret=Role.objects.filter(user=user)
        permissions = Role.objects.filter(user__name=user).values("permissions__url",
                                                            "permissions__is_menu",
                                                            "permissions__title",
                                                            "permissions__icon",
                                                            ).distinct()
        permission_list = []
        permission_menu_list = []
        for item in permissions:
            # 构建权限列表
            permission_list.append(item["permissions__url"])
    
            # 构建菜单权限列表
            if item["permissions__is_menu"]:
                permission_menu_list.append({
                    "title":item["permissions__title"],
                    "icon":item["permissions__icon"],
                    "url":item["permissions__url"],
                })

        # 将当前登录人的权限列表注入session
        request.session["permission_list"] = permission_list
        # 将当前登录人的菜单权限列表注入session
        print("permission_menu_list",permission_menu_list)
        request.session["permission_menu_list"] = permission_menu_list

    (4)在母板中,循环request.session构建左侧菜单a标签

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>掌上大学</title>
    </head>
    <body>
    <div>
        {% for foo in request.session.permission_menu_list %}
            <a href="{{ foo.url }}">{{ foo.title }}</a>
        {% endfor %}
        
        {% block content %}
        {% endblock %}
    </div>
    </body>
    </html>

    三. 为每个左侧菜单动态添加active

    缺点:要在每一个菜单视图函数中添加这样一段代码

    .(自定义过滤器(look)和标签)为每个左侧菜单动态添加active,改进方式准备知识

    1.自定义过滤器

    自定义过滤器的步骤:

    (1)检查settings中的install_app是否包含该app

    (2)APP下加一个包:必须叫templatetags

    (3)建一个python脚本:名字随意

    (4)在该脚本中:

    from django.template import Library
    register=Library()  #前两句是固定的

    @register.filter    #让一个函数变成过滤器的语法
    def mul(x):
        return x*2

    (5)HTML中的应用语法:

    {% load glq %}  #遇到load,Django会固定循环每一个app下的templatetags语法
    {{ 2|mul }}  #如果有其他参数,放在函数名后,用空格隔开

    (4) 写完要重启项目,过滤器才能用用

    2.可以渲染标签的过滤器

    (1)过滤器的编写

    from django.template import Library
    register=Library()
    from django.utils.safestring import mark_safe  #

    @register.filter
    def tag(val):
        return mark_safe("<a href='www.baidu.com'>%s</a>" % val)

    (2) HTML中的应用:

    {% load glq %}
    {{ '点击跳转'|tag }}

    自定义过滤器的局限性:参数最多只能有两个

    3.自定义标签

    语法:与自定义过滤器语法大体相同

    不同之处:

    (1)@register.simple_tag  #让一个函数变成自定义标签的语法
    def mul_tag(x,y,z):
        return x*y*z

    (2)HTML:

    {% load glq %}
    {% mul_tag 2 3 5 %} 前者用{{   }}调用,欧后者用{%   %}调用

    4.includsion_tags:将母版和自定义标签结合

    (1)定义includsion_tags:

    @register.inclusion_tag("web/menu.html")
    def get_menu_style(request):
        menu_list=[11,22,33]
        return {"menu_list":menu_list}  #返回值尽量用字典,要不然会报错

    (2)编写用到的menu.html:

    <ul>
        {% for foo in menu_list %}
        <li>{{ foo }}</li>
        {% endfor %}
    </ul>

    (3) HTML中的调用:

    {% load glq %}
    {% get_menu_style request %}

    优点:数据之需要传一次

    所以:!!!!!!!!!

    对于动态添加active需求的处理

    让母版调用get_menu_styles方法:

    @register.inclusion_tag("web/menu.html")
    def get_menu_styles(request):
        permission_menu_list = request.session.get("permission_menu_list")
        for item in permission_menu_list:
            if re.search("^{}$".format(item["url"]), request.path):
                item["class"] = "active"
        return {"permission_menu_list":permission_menu_list}

    menu.html:

    <ul>
        {% for foo in menu_list %}
        <li>{{ foo }}</li>
        {% endfor %}
    </ul>

    .在浏览器访问一个页面的过程中render到底做了什么

    .母版继承补充:

    母版继承除了可以在在所继承的母版中添加某一部分内容外,还可以在一个完整的HTML中的某一部分使用另一个HTML

    语法:{% include "web/other.html" %}

    .补充细节问题:

    Ajax想发送一个这样的name

    一定要加”    ”

    如果把js抽出来,可以在HTML页面中添加一个没有用的标签,<div class={{ name }}></div>用来存储{{ class }}

  • 相关阅读:
    Redis源码解析(十五)--- aof-append only file解析
    Redis源码解析(十五)--- aof-append only file解析
    Redis源码解析(十五)--- aof-append only file解析
    Storm的起源概况
    Storm的起源概况
    Storm的起源概况
    Storm的基本知识
    Storm的基本知识
    Storm的基本知识
    Redis源码解析(十六)--- config配置文件
  • 原文地址:https://www.cnblogs.com/shanghongyun/p/9871503.html
Copyright © 2011-2022 走看看