【案例】权限管理

数据库表结构
models.py

from django.db import models


class Permission(models.Model):
    """ 权限表 """
    code = models.CharField(verbose_name="路由名称", max_length=32)
    name = models.CharField(verbose_name="名称", max_length=32)


class Role(models.Model):
    """ 角色表 """
    name = models.CharField(verbose_name="名称", max_length=32)

    permissions = models.ManyToManyField(verbose_name="权限", to="Permission")


class User(models.Model):
    """ 用户表 """
    username = models.CharField(verbose_name="用户名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=32)
    is_super = models.BooleanField(verbose_name="是否管理员", default=False)

    roles = models.ManyToManyField(verbose_name="权限", to="Role")


class Computer(models.Model):
    """ 电脑 """
    title = models.CharField(verbose_name="名称", max_length=32)
    price = models.IntegerField(verbose_name="价格")


class Order(models.Model):
    """ 订单 """
    title = models.CharField(verbose_name="订单", max_length=32)
    price = models.IntegerField(verbose_name="价格")

使用命令行创建超级用户
management/commands/superuser.py

from django.core.management.base import BaseCommand
from www import models


class Command(BaseCommand):
    def handle(self, *args, **options):
        username = input("请输入用户名:")
        password = input("请输入密码:")

        models.User.objects.create(username=username, password=password, is_super=True)

使用离线脚本创建角色和用户
scripts/创建普通用户及权限.py

import django
import os
import sys

base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_dir)

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rbac.settings')
django.setup()

from www import models
#
# models.Permission.objects.bulk_create([
#     models.Permission(code="computer", name="电脑管理"),
#     models.Permission(code="computer_add", name="电脑添加"),
#     models.Permission(code="computer_edit", name="电脑编辑"),
#     models.Permission(code="computer_del", name="电脑删除"),
# ])
#
# role = models.Role.objects.create(name="运营实习生")
# role.permissions.set([1, 2])
#
# role = models.Role.objects.create(name="正式员工")
# role.permissions.set([1, 2, 3, 4])
#
# user = models.User.objects.create(username="cqn", password="123", is_super=False)
# user.roles.set([1])
#
# user = models.User.objects.create(username="zkf", password="123", is_super=False)
# user.roles.set([1, 2])

urls.py

"""
URL configuration for rbac project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.urls import path
from www import views

urlpatterns = [
    path('login/', views.login, name="login"),
    path('home/', views.home, name="home"),

    path('computer/', views.computer, name="computer"),
    path('computer/add/', views.computer_add, name="computer_add"),
    path('computer/edit/<int:id>/', views.computer_edit, name="computer_edit"),
    path('computer/del/<int:id>/', views.computer_del, name="computer_del"),

    path('order/', views.order, name="order"),
    path('order/add/', views.order_add, name="order_add"),
    path('order/edit/<int:id>/', views.order_edit, name="order_edit"),
    path('order/del/<int:id>/', views.order_del, name="order_del"),
]

views.py

from django.shortcuts import render, HttpResponse, redirect
from django.forms import ModelForm
from django.forms.models import model_to_dict
from www import models


class LoginModelForm(ModelForm):
    class Meta:
        model = models.User
        fields = ["username", "password"]


def login(request):
    if request.method == "GET":
        form = LoginModelForm()
        return render(request, "login.html", {"form": form})

    form = LoginModelForm(data=request.POST)
    if not form.is_valid():
        return render(request, "login.html", {"form": form})

    user_object = models.User.objects.filter(**form.cleaned_data).first()
    if not user_object:
        form.add_error("password", "用户名或密码错误")
        return render(request, "login.html", {"form": form})

    # request.session["user_session_key"] = {
    #     "id": user_object.id,
    #     "username": user_object.username,
    #     "is_super": user_object.is_super
    # }
    request.session["user_session_key"] = model_to_dict(user_object, fields=["id", "username", "is_super"])
    return redirect("home")


def home(request):
    return HttpResponse("HOME")


def computer(request):
    return render(request, 'computer.html')


def computer_add(request):
    return HttpResponse("OK")


def computer_edit(request, id):
    return HttpResponse("OK")


def computer_del(request, id):
    return HttpResponse("OK")


def order(request):
    return HttpResponse("OK")


def order_add(request):
    return HttpResponse("OK")


def order_edit(request, id):
    return HttpResponse("OK")


def order_del(request, id):
    return HttpResponse("OK")

中间件
utils/md.py

from django.contrib.auth.middleware import MiddlewareMixin
from django.urls import reverse
from django.shortcuts import redirect, HttpResponse
from www import models


class AuthMiddleware(MiddlewareMixin):
    def process_request(self, request):
        if request.path_info in [reverse("login")]:
            return

        user_dict = request.session.get("user_session_key")
        if not user_dict:
            return redirect("login")

        request.user_dict = user_dict


class PermissionMiddleware(MiddlewareMixin):
    def process_view(self, request, callback, *args, **kwargs):
        if request.path_info in [reverse("login")]:
            return

        if request.user_dict["is_super"]:
            return

        # 用户访问的rl
        url_name = request.resolver_match.url_name
        print("PermissionMiddleware中间件: ", url_name)

        # 用户对象
        user_object = models.User.objects.filter(id=request.user_dict['id']).first()

        # 用户所有的角色,角色对应的权限
        user_per_list = user_object.roles.all().values("permissions__code", "permissions__name")
        permission_dict = {item["permissions__code"]: item["permissions__name"] for item in user_per_list}
        print("PermissionMiddleware中间件: ", permission_dict)

        request.permission_dict = permission_dict

        if url_name in permission_dict:
            return

        return HttpResponse("无权访问")

前端页面
templates/login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>用户登录</h2>
<form method="post" novalidate>
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">登录</button>
</form>

</body>
</html>

templates/computer.html

{% load permission %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% if request|has_permission:"computer_add" %}
    <a href="{% url "computer_add" %}">新增</a>
{% endif %}

{% if request|has_permission:"computer_edit" %}
    <a href="{% url "computer_edit" id=1 %}">编辑</a>
{% endif %}

{% if request|has_permission:"computer_del" %}
    <a href="{% url "computer_del" id=1 %}">删除</a>
{% endif %}

</body>
</html>

templatetags/permission.py

from django.template import Library

register = Library()


@register.filter
def has_permission(request, route_name):
    is_super = request.user_dict['is_super']
    if is_super:
        return True

    if route_name in request.permission_dict:
        return True

    return False

路由管理

views.py

from django.shortcuts import render, HttpResponse, redirect
from django.forms import ModelForm
from django.forms.models import model_to_dict
from www import models


class LoginModelForm(ModelForm):
    class Meta:
        model = models.User
        fields = ["username", "password"]


def login(request):
    if request.method == "GET":
        form = LoginModelForm()
        return render(request, "login.html", {"form": form})

    form = LoginModelForm(data=request.POST)
    if not form.is_valid():
        return render(request, "login.html", {"form": form})

    user_object = models.User.objects.filter(**form.cleaned_data).first()
    if not user_object:
        form.add_error("password", "用户名或密码错误")
        return render(request, "login.html", {"form": form})

    # request.session["user_session_key"] = {
    #     "id": user_object.id,
    #     "username": user_object.username,
    #     "is_super": user_object.is_super
    # }
    request.session["user_session_key"] = model_to_dict(user_object, fields=["id", "username", "is_super"])
    return redirect("home")


def home(request):
    return HttpResponse("HOME")


from django.conf import settings
from importlib import import_module
from django.urls.resolvers import URLResolver, URLPattern


def get_all_url_permission():
    # 1、找到根路由 settings.ROOT_URLCONF, 'rbac.urls'
    root = import_module(settings.ROOT_URLCONF)

    # 2、找到跟路由列表
    # print(root.urlpatterns)
    #
    # for obj in root.urlpatterns:
    #     if type(obj) == URLPattern:
    #         print("URLPattern: ", obj)
    #         continue
    #     if type(obj) == URLResolver:
    #         print("URLResolver: ", obj.url_patterns)
    #         for item in obj.url_patterns:
    #             print("\t", item)

    # 4、多层级的路由处理
    resolver_list = [root]
    for resolver in resolver_list:
        # patterns = resolver.urlpatterns  或者 resolver.url_patterns
        patterns = getattr(resolver, "urlpatterns", None) or getattr(resolver, "url_patterns", None)
        for item in patterns:
            if type(item) == URLPattern:
                print("URLPattern: ", item.name, item)
                continue
            if type(item) == URLResolver:
                resolver_list.append(item)


def permission(request):
    if request.method == "POST":
        # 1、读取项目中所有权限(路由)
        data = get_all_url_permission()
        pass

    queryset = models.Permission.objects.all()
    return render(request, 'permission.html', {"queryset": queryset})


def computer(request):
    return render(request, 'computer.html')


def computer_add(request):
    return HttpResponse("OK")


def computer_edit(request, id):
    return HttpResponse("OK")


def computer_del(request, id):
    return HttpResponse("OK")


def order(request):
    return HttpResponse("OK")


def order_add(request):
    return HttpResponse("OK")


def order_edit(request, id):
    return HttpResponse("OK")


def order_del(request, id):
    return HttpResponse("OK")

rbac/urls.py

"""
URL configuration for rbac project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.urls import path, include
from www import views

urlpatterns = [
    path('login/', views.login, name="login"),
    path('home/', views.home, name="home"),

    path('permission/', views.permission, name="permission"),

    path('computer/', views.computer, name="computer"),
    path('computer/add/', views.computer_add, name="computer_add"),
    path('computer/edit/<int:id>/', views.computer_edit, name="computer_edit"),
    path('computer/del/<int:id>/', views.computer_del, name="computer_del"),

    path('order/', views.order, name="order"),
    path('order/add/', views.order_add, name="order_add"),
    path('order/edit/<int:id>/', views.order_edit, name="order_edit"),
    path('order/del/<int:id>/', views.order_del, name="order_del"),

    path('app01/', include("app01.urls")),
    path('app02/', include("app02.urls")),
]

app01/urls.py

from django.urls import path
from app01 import views

urlpatterns = [
    path('test1/', views.test1, name="test1")
]

添加路由的中文信息
utils/ext_urls.py

from functools import partial
from importlib import import_module

from django.core.exceptions import ImproperlyConfigured

from django.urls.resolvers import (
    LocalePrefixPattern,
    RegexPattern,
    RoutePattern,
    URLPattern,
    URLResolver,
)


class RbacPattern(URLPattern):
    def __init__(self, pattern, callback, default_args=None, name=None, text=None):
        super().__init__(pattern, callback, default_args, name)
        self.text = text


def _path(route, view, kwargs=None, name=None, text=None, Pattern=None):
    from django.views import View

    if kwargs is not None and not isinstance(kwargs, dict):
        raise TypeError(
            f"kwargs argument must be a dict, but got {kwargs.__class__.__name__}."
        )
    if isinstance(view, (list, tuple)):
        # For include(...) processing.
        pattern = Pattern(route, is_endpoint=False)
        urlconf_module, app_name, namespace = view
        return URLResolver(
            pattern,
            urlconf_module,
            kwargs,
            app_name=app_name,
            namespace=namespace,
        )
    elif callable(view):
        pattern = Pattern(route, name=name, is_endpoint=True)
        return RbacPattern(pattern, view, kwargs, name, text)
    elif isinstance(view, View):
        view_cls_name = view.__class__.__name__
        raise TypeError(
            f"view must be a callable, pass {view_cls_name}.as_view(), not "
            f"{view_cls_name}()."
        )
    else:
        raise TypeError(
            "view must be a callable or a list/tuple in the case of include()."
        )


rbac_path = partial(_path, Pattern=RoutePattern)
rbac_re_path = partial(_path, Pattern=RegexPattern)

urls.py

"""
URL configuration for rbac project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.urls import path, include
from www import views
from www.utils.ext_url import rbac_path

urlpatterns = [
    path('login/', views.login, name="login"),
    rbac_path('home/', views.home, name="home", text="家目录"),
    # rbac_path('demo/', views.home, name="demo", text="测试"),

    rbac_path('permission/', views.permission, name="permission", text="权限管理"),

    rbac_path('computer/', views.computer, name="computer", text="电脑管理"),
    rbac_path('computer/add/', views.computer_add, name="computer_add", text="电脑增加"),
    rbac_path('computer/edit/<int:id>/', views.computer_edit, name="computer_edit", text="电脑编辑"),
    rbac_path('computer/del/<int:id>/', views.computer_del, name="computer_del", text="电脑删除"),

    rbac_path('order/', views.order, name="order", text="订单管理"),
    rbac_path('order/add/', views.order_add, name="order_add", text="订单增加"),
    rbac_path('order/edit/<int:id>/', views.order_edit, name="order_edit", text="订单编辑"),
    rbac_path('order/del/<int:id>/', views.order_del, name="order_del", text="订单删除"),

    rbac_path('app01/', include("app01.urls")),
    rbac_path('app02/', include("app02.urls", namespace='app02')),
]

app02/urls.py

from app02 import views
from www.utils.ext_url import rbac_path

urlpatterns = [
    rbac_path('test2/', views.test2, name="test2", text="test2"),
    rbac_path('test3/', views.test3, name="test3", text="test3")
]

app_name = "app02"

views.py

from django.shortcuts import render, HttpResponse, redirect
from django.forms import ModelForm
from django.forms.models import model_to_dict
from www import models


class LoginModelForm(ModelForm):
    class Meta:
        model = models.User
        fields = ["username", "password"]


def login(request):
    if request.method == "GET":
        form = LoginModelForm()
        return render(request, "login.html", {"form": form})

    form = LoginModelForm(data=request.POST)
    if not form.is_valid():
        return render(request, "login.html", {"form": form})

    user_object = models.User.objects.filter(**form.cleaned_data).first()
    if not user_object:
        form.add_error("password", "用户名或密码错误")
        return render(request, "login.html", {"form": form})

    # request.session["user_session_key"] = {
    #     "id": user_object.id,
    #     "username": user_object.username,
    #     "is_super": user_object.is_super
    # }
    request.session["user_session_key"] = model_to_dict(user_object, fields=["id", "username", "is_super"])
    return redirect("home")


def home(request):
    return HttpResponse("HOME")


from django.conf import settings
from importlib import import_module
from django.urls.resolvers import URLResolver, URLPattern
from www.utils.ext_url import RbacPattern


def get_all_url_permission():
    # 1、找到根路由 settings.ROOT_URLCONF, 'rbac.urls'
    root = import_module(settings.ROOT_URLCONF)

    # 2、找到跟路由列表
    # print(root.urlpatterns)
    #
    # for obj in root.urlpatterns:
    #     if type(obj) == URLPattern:
    #         print("URLPattern: ", obj)
    #         continue
    #     if type(obj) == URLResolver:
    #         print("URLResolver: ", obj.url_patterns)
    #         for item in obj.url_patterns:
    #             print("\t", item)

    # 4、多层级的路由处理
    resolver_list = [(root, None)]
    local_dict = {}
    for resolver, pre_namespace in resolver_list:
        # patterns = resolver.urlpatterns  或者 resolver.url_patterns
        patterns = getattr(resolver, "urlpatterns", None) or getattr(resolver, "url_patterns", None)
        for item in patterns:
            # if type(item) == URLPattern:
            #     print("URLPattern: ", item.name, item)
            #     continue
            if type(item) == RbacPattern:
                # print("RbacPattern: ", item.name, item)
                code = f"{pre_namespace}:{item.name}" if pre_namespace else item.name
                local_dict[code] = item.text
                continue
            if type(item) == URLResolver:
                namespace_list = [ele for ele in [pre_namespace, item.namespace] if ele]
                total_namespace = ":".join(namespace_list) if namespace_list else None
                resolver_list.append((item, total_namespace))
    return local_dict


def permission(request):
    if request.method == "POST":
        # 1、读取项目中所有权限(路由)
        local_route_dict = get_all_url_permission()
        local_route_set = set(local_route_dict)

        # 2、读物数据库已有权限(路由)
        db_pers = models.Permission.objects.all()
        db_pers_dict = {item.code: item.name for item in db_pers}
        db_pers_set = set(db_pers_dict)

        # 3、对比:增加、删除、更新
        # 增加
        models.Permission.objects.bulk_create(
            [models.Permission(code=code, name=local_route_dict[code]) for code in local_route_set - db_pers_set]
        )
        # 删除
        models.Permission.objects.filter(code__in=db_pers_set - local_route_set).delete()

        # 更新
        for code in db_pers_set & local_route_set:
            if db_pers_dict[code] == local_route_dict[code]:
                continue
            models.Permission.objects.filter(code=code).update(name=local_route_dict[code])

    queryset = models.Permission.objects.all()
    return render(request, 'permission.html', {"queryset": queryset})


def computer(request):
    return render(request, 'computer.html')


def computer_add(request):
    return HttpResponse("OK")


def computer_edit(request, id):
    return HttpResponse("OK")


def computer_del(request, id):
    return HttpResponse("OK")


def order(request):
    return HttpResponse("OK")


def order_add(request):
    return HttpResponse("OK")


def order_edit(request, id):
    return HttpResponse("OK")


def order_del(request, id):
    return HttpResponse("OK")

用户管理和角色管理

urls.py

from django.urls import path, include
from www import views
from www.utils.ext_url import rbac_path

urlpatterns = [
    path('login/', views.login, name="login"),
    rbac_path('home/', views.home, name="home", text="家目录"),
    # rbac_path('demo/', views.home, name="demo", text="测试"),

    rbac_path('permission/', views.permission, name="permission", text="权限管理"),

    rbac_path('computer/', views.computer, name="computer", text="电脑管理"),
    rbac_path('computer/add/', views.computer_add, name="computer_add", text="电脑增加"),
    rbac_path('computer/edit/<int:id>/', views.computer_edit, name="computer_edit", text="电脑编辑"),
    rbac_path('computer/del/<int:id>/', views.computer_del, name="computer_del", text="电脑删除"),

    rbac_path('role/', views.role, name="role", text="角色管理"),
    rbac_path('role/add/', views.role_add, name="role_add", text="角色增加"),
    rbac_path('role/edit/<int:id>/', views.role_edit, name="role_edit", text="角色编辑"),
    rbac_path('role/del/<int:id>/', views.role_del, name="role_del", text="角色删除"),

    rbac_path('user/', views.user, name="user", text="用户管理"),
    rbac_path('user/add/', views.user_add, name="user_add", text="用户增加"),
    rbac_path('user/edit/<int:id>/', views.user_edit, name="user_edit", text="用户编辑"),
    rbac_path('user/del/<int:id>/', views.user_del, name="user_del", text="用户删除"),

    rbac_path('order/', views.order, name="order", text="订单管理"),
    rbac_path('order/add/', views.order_add, name="order_add", text="订单增加"),
    rbac_path('order/edit/<int:id>/', views.order_edit, name="order_edit", text="订单编辑"),
    rbac_path('order/del/<int:id>/', views.order_del, name="order_del", text="订单删除"),

    rbac_path('app01/', include("app01.urls")),
    rbac_path('app02/', include("app02.urls", namespace='app02')),
]

view.py

from django.shortcuts import render, HttpResponse, redirect
from django.forms import ModelForm
from django.forms.models import model_to_dict
from www import models


class LoginModelForm(ModelForm):
    class Meta:
        model = models.User
        fields = ["username", "password"]


def login(request):
    if request.method == "GET":
        form = LoginModelForm()
        return render(request, "login.html", {"form": form})

    form = LoginModelForm(data=request.POST)
    if not form.is_valid():
        return render(request, "login.html", {"form": form})

    user_object = models.User.objects.filter(**form.cleaned_data).first()
    if not user_object:
        form.add_error("password", "用户名或密码错误")
        return render(request, "login.html", {"form": form})

    # request.session["user_session_key"] = {
    #     "id": user_object.id,
    #     "username": user_object.username,
    #     "is_super": user_object.is_super
    # }
    request.session["user_session_key"] = model_to_dict(user_object, fields=["id", "username", "is_super"])
    return redirect("home")


def home(request):
    return HttpResponse("HOME")


from django.conf import settings
from importlib import import_module
from django.urls.resolvers import URLResolver, URLPattern
from www.utils.ext_url import RbacPattern


def get_all_url_permission():
    # 1、找到根路由 settings.ROOT_URLCONF, 'rbac.urls'
    root = import_module(settings.ROOT_URLCONF)

    # 2、找到跟路由列表
    # print(root.urlpatterns)
    #
    # for obj in root.urlpatterns:
    #     if type(obj) == URLPattern:
    #         print("URLPattern: ", obj)
    #         continue
    #     if type(obj) == URLResolver:
    #         print("URLResolver: ", obj.url_patterns)
    #         for item in obj.url_patterns:
    #             print("\t", item)

    # 4、多层级的路由处理
    resolver_list = [(root, None)]
    local_dict = {}
    for resolver, pre_namespace in resolver_list:
        # patterns = resolver.urlpatterns  或者 resolver.url_patterns
        patterns = getattr(resolver, "urlpatterns", None) or getattr(resolver, "url_patterns", None)
        for item in patterns:
            # if type(item) == URLPattern:
            #     print("URLPattern: ", item.name, item)
            #     continue
            if type(item) == RbacPattern:
                # print("RbacPattern: ", item.name, item)
                code = f"{pre_namespace}:{item.name}" if pre_namespace else item.name
                local_dict[code] = item.text
                continue
            if type(item) == URLResolver:
                namespace_list = [ele for ele in [pre_namespace, item.namespace] if ele]
                total_namespace = ":".join(namespace_list) if namespace_list else None
                resolver_list.append((item, total_namespace))
    return local_dict


def permission(request):
    if request.method == "POST":
        # 1、读取项目中所有权限(路由)
        local_route_dict = get_all_url_permission()
        local_route_set = set(local_route_dict)

        # 2、读物数据库已有权限(路由)
        db_pers = models.Permission.objects.all()
        db_pers_dict = {item.code: item.name for item in db_pers}
        db_pers_set = set(db_pers_dict)

        # 3、对比:增加、删除、更新
        # 增加
        models.Permission.objects.bulk_create(
            [models.Permission(code=code, name=local_route_dict[code]) for code in local_route_set - db_pers_set]
        )
        # 删除
        models.Permission.objects.filter(code__in=db_pers_set - local_route_set).delete()

        # 更新
        for code in db_pers_set & local_route_set:
            if db_pers_dict[code] == local_route_dict[code]:
                continue
            models.Permission.objects.filter(code=code).update(name=local_route_dict[code])

    queryset = models.Permission.objects.all()
    return render(request, 'permission.html', {"queryset": queryset})


def computer(request):
    return render(request, 'computer.html')


def computer_add(request):
    return HttpResponse("OK")


def computer_edit(request, id):
    return HttpResponse("OK")


def computer_del(request, id):
    return HttpResponse("OK")


class RoleModelForm(ModelForm):
    class Meta:
        model = models.Role
        fields = "__all__"


def role(request):
    queryset = models.Role.objects.all()
    return render(request, 'role.html', {"queryset": queryset})


def role_add(request):
    if request.method == "GET":
        form = RoleModelForm()
        return render(request, 'form.html', {"form": form})

    form = RoleModelForm(data=request.POST)
    if not form.is_valid():
        return render(request, 'form.html', {"form": form})

    form.save()
    return redirect(to="role")


def role_edit(request, id):
    instance = models.Role.objects.filter(id=id).first()

    if request.method == "GET":
        form = RoleModelForm(instance=instance)
        return render(request, 'form.html', {"form": form})

    form = RoleModelForm(data=request.POST, instance=instance)
    if not form.is_valid():
        return render(request, 'form.html', {"form": form})

    form.save()
    return redirect(to="role")


def role_del(request, id):
    models.Role.objects.filter(id=id).first().delete()
    return redirect(to="role")


class UserModelForm(ModelForm):
    class Meta:
        model = models.User
        fields = "__all__"


def user(request):
    if request.method == "GET":
        queryset = models.User.objects.all()
        return render(request, "user.html", {"queryset": queryset})
    return HttpResponse("OK")


def user_add(request):
    if request.method == "GET":
        form = UserModelForm()
        return render(request, "form.html", {"form": form})

    form = UserModelForm(data=request.POST)
    if not form.is_valid():
        return render(request, "form.html", {"form": form})

    form.save()
    return redirect(to="user")


def user_edit(request, id):
    instance = models.User.objects.filter(id=id).first()
    if request.method == "GET":
        form = UserModelForm(instance=instance)
        return render(request, "form.html", {"form": form})
    form = UserModelForm(instance=instance, data=request.POST)
    if not form.is_valid():
        return render(request, "user.html", {"form": form})
    form.save()
    return redirect(to="user")


def user_del(request, id):
    models.User.objects.filter(id=id).delete()
    return redirect(to="user")


def order(request):
    return HttpResponse("OK")


def order_add(request):
    return HttpResponse("OK")


def order_edit(request, id):
    return HttpResponse("OK")


def order_del(request, id):
    return HttpResponse("OK")

form.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form method="post" novalidate>
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">提交</button>
</form>

</body>
</html>

role.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="{% url 'role_add' %}">新增</a>
<table border="1">
    <thead>
    <tr>
        <th>ID</th>
        <th>名称</th>
        <th>操作</th>
    </tr>
    </thead>
    <tbody>
    {% for row in queryset %}
        <tr>
            <td>{{ row.id }}</td>
            <td>{{ row.name }}</td>
            <td>
                <a href="{% url 'role_edit' id=row.id %}">编辑</a>
                <a href="{% url 'role_del' id=row.id %}">删除</a>
            </td>
        </tr>
    {% endfor %}
    </tbody>
</table>

</body>
</html>

user.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<a href="{% url 'user_add' %}">新增</a>
<table border="1">
    <thead>
    <tr>
        <th>用户名</th>
        <th>密码</th>
        <th>超级管理员</th>
        <th>操作</th>
    </tr>
    </thead>
    <tbody>
    {% for row in queryset %}
        <tr>
            <td>{{ row.username }}</td>
            <td>{{ row.password }}</td>
            <td>{{ row.is_super }}</td>
            <td>
                <a href="{% url 'user_edit' id=row.id %}">编辑</a>
                <a href="{% url 'user_del' id=row.id %}">删除</a>
            </td>
        </tr>
    {% endfor %}
    </tbody>
</table>

</body>
</html>

添加菜单管理
models.py

from django.db import models


class Permission(models.Model):
    """ 权限表 """
    code = models.CharField(verbose_name="路由名称", max_length=32)
    name = models.CharField(verbose_name="名称", max_length=32)

    def __str__(self):
        return self.name


class Role(models.Model):
    """ 角色表 """
    name = models.CharField(verbose_name="名称", max_length=32)

    permissions = models.ManyToManyField(verbose_name="权限", to="Permission")

    def __str__(self):
        return self.name


class User(models.Model):
    """ 用户表 """
    username = models.CharField(verbose_name="用户名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=32)
    is_super = models.BooleanField(verbose_name="是否管理员", default=False)

    roles = models.ManyToManyField(verbose_name="权限", to="Role", blank=True)
    menus = models.ManyToManyField(verbose_name="菜单", to="Menu", blank=True)


class Computer(models.Model):
    """ 电脑 """
    title = models.CharField(verbose_name="名称", max_length=32)
    price = models.IntegerField(verbose_name="价格")


class Order(models.Model):
    """ 订单 """
    title = models.CharField(verbose_name="订单", max_length=32)
    price = models.IntegerField(verbose_name="价格")


class Menu(models.Model):
    """ 菜单 """
    title = models.CharField(verbose_name="名称", max_length=32)
    permissions = models.ManyToManyField(verbose_name="权限", to="Permission")

    def __str__(self):
        return self.title

urls.py

"""
URL configuration for rbac project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.urls import path, include
from www import views
from www.utils.ext_url import rbac_path

urlpatterns = [
    path('login/', views.login, name="login"),
    rbac_path('home/', views.home, name="home", text="家目录"),
    # rbac_path('demo/', views.home, name="demo", text="测试"),

    rbac_path('permission/', views.permission, name="permission", text="权限管理"),

    rbac_path('computer/', views.computer, name="computer", text="电脑管理"),
    rbac_path('computer/add/', views.computer_add, name="computer_add", text="电脑增加"),
    rbac_path('computer/edit/<int:id>/', views.computer_edit, name="computer_edit", text="电脑编辑"),
    rbac_path('computer/del/<int:id>/', views.computer_del, name="computer_del", text="电脑删除"),

    rbac_path('role/', views.role, name="role", text="角色管理"),
    rbac_path('role/add/', views.role_add, name="role_add", text="角色增加"),
    rbac_path('role/edit/<int:id>/', views.role_edit, name="role_edit", text="角色编辑"),
    rbac_path('role/del/<int:id>/', views.role_del, name="role_del", text="角色删除"),

    rbac_path('user/', views.user, name="user", text="用户管理"),
    rbac_path('user/add/', views.user_add, name="user_add", text="用户增加"),
    rbac_path('user/edit/<int:id>/', views.user_edit, name="user_edit", text="用户编辑"),
    rbac_path('user/del/<int:id>/', views.user_del, name="user_del", text="用户删除"),

    rbac_path('order/', views.order, name="order", text="订单管理"),
    rbac_path('order/add/', views.order_add, name="order_add", text="订单增加"),
    rbac_path('order/edit/<int:id>/', views.order_edit, name="order_edit", text="订单编辑"),
    rbac_path('order/del/<int:id>/', views.order_del, name="order_del", text="订单删除"),

    rbac_path('menu/', views.menu, name="menu", text="菜单管理"),
    rbac_path('menu/add/', views.menu_add, name="menu_add", text="菜单增加"),
    rbac_path('menu/edit/<int:id>/', views.menu_edit, name="menu_edit", text="菜单编辑"),
    rbac_path('menu/del/<int:id>/', views.menu_del, name="menu_del", text="菜单删除"),

    # rbac_path('app01/', include("app01.urls")),
    # rbac_path('app02/', include("app02.urls", namespace='app02')),
]

views.py

from django.shortcuts import render, HttpResponse, redirect
from django.forms import ModelForm
from django.forms.models import model_to_dict
from www import models


class LoginModelForm(ModelForm):
    class Meta:
        model = models.User
        fields = ["username", "password"]


def login(request):
    if request.method == "GET":
        form = LoginModelForm()
        return render(request, "login.html", {"form": form})

    form = LoginModelForm(data=request.POST)
    if not form.is_valid():
        return render(request, "login.html", {"form": form})

    user_object = models.User.objects.filter(**form.cleaned_data).first()
    if not user_object:
        form.add_error("password", "用户名或密码错误")
        return render(request, "login.html", {"form": form})

    # request.session["user_session_key"] = {
    #     "id": user_object.id,
    #     "username": user_object.username,
    #     "is_super": user_object.is_super
    # }
    request.session["user_session_key"] = model_to_dict(user_object, fields=["id", "username", "is_super"])
    return redirect("home")


def home(request):
    return render(request, "home.html")


from django.conf import settings
from importlib import import_module
from django.urls.resolvers import URLResolver, URLPattern
from www.utils.ext_url import RbacPattern


def get_all_url_permission():
    # 1、找到根路由 settings.ROOT_URLCONF, 'rbac.urls'
    root = import_module(settings.ROOT_URLCONF)

    # 2、找到跟路由列表
    # print(root.urlpatterns)
    #
    # for obj in root.urlpatterns:
    #     if type(obj) == URLPattern:
    #         print("URLPattern: ", obj)
    #         continue
    #     if type(obj) == URLResolver:
    #         print("URLResolver: ", obj.url_patterns)
    #         for item in obj.url_patterns:
    #             print("\t", item)

    # 4、多层级的路由处理
    resolver_list = [(root, None)]
    local_dict = {}
    for resolver, pre_namespace in resolver_list:
        # patterns = resolver.urlpatterns  或者 resolver.url_patterns
        patterns = getattr(resolver, "urlpatterns", None) or getattr(resolver, "url_patterns", None)
        for item in patterns:
            # if type(item) == URLPattern:
            #     print("URLPattern: ", item.name, item)
            #     continue
            if type(item) == RbacPattern:
                # print("RbacPattern: ", item.name, item)
                code = f"{pre_namespace}:{item.name}" if pre_namespace else item.name
                local_dict[code] = item.text
                continue
            if type(item) == URLResolver:
                namespace_list = [ele for ele in [pre_namespace, item.namespace] if ele]
                total_namespace = ":".join(namespace_list) if namespace_list else None
                resolver_list.append((item, total_namespace))
    return local_dict


def permission(request):
    if request.method == "POST":
        # 1、读取项目中所有权限(路由)
        local_route_dict = get_all_url_permission()
        local_route_set = set(local_route_dict)

        # 2、读物数据库已有权限(路由)
        db_pers = models.Permission.objects.all()
        db_pers_dict = {item.code: item.name for item in db_pers}
        db_pers_set = set(db_pers_dict)

        # 3、对比:增加、删除、更新
        # 增加
        models.Permission.objects.bulk_create(
            [models.Permission(code=code, name=local_route_dict[code]) for code in local_route_set - db_pers_set]
        )
        # 删除
        models.Permission.objects.filter(code__in=db_pers_set - local_route_set).delete()

        # 更新
        for code in db_pers_set & local_route_set:
            if db_pers_dict[code] == local_route_dict[code]:
                continue
            models.Permission.objects.filter(code=code).update(name=local_route_dict[code])

    queryset = models.Permission.objects.all()
    return render(request, 'permission.html', {"queryset": queryset})


def computer(request):
    return render(request, 'computer.html')


def computer_add(request):
    return HttpResponse("OK")


def computer_edit(request, id):
    return HttpResponse("OK")


def computer_del(request, id):
    return HttpResponse("OK")


class RoleModelForm(ModelForm):
    class Meta:
        model = models.Role
        fields = "__all__"


def role(request):
    queryset = models.Role.objects.all()
    return render(request, 'role.html', {"queryset": queryset})


def role_add(request):
    if request.method == "GET":
        form = RoleModelForm()
        return render(request, 'form.html', {"form": form})

    form = RoleModelForm(data=request.POST)
    if not form.is_valid():
        return render(request, 'form.html', {"form": form})

    form.save()
    return redirect(to="role")


def role_edit(request, id):
    instance = models.Role.objects.filter(id=id).first()

    if request.method == "GET":
        form = RoleModelForm(instance=instance)
        return render(request, 'form.html', {"form": form})

    form = RoleModelForm(data=request.POST, instance=instance)
    if not form.is_valid():
        return render(request, 'form.html', {"form": form})

    form.save()
    return redirect(to="role")


def role_del(request, id):
    models.Role.objects.filter(id=id).first().delete()
    return redirect(to="role")


class UserModelForm(ModelForm):
    class Meta:
        model = models.User
        fields = "__all__"


def user(request):
    if request.method == "GET":
        queryset = models.User.objects.all()
        return render(request, "user.html", {"queryset": queryset})
    return HttpResponse("OK")


def user_add(request):
    if request.method == "GET":
        form = UserModelForm()
        return render(request, "form.html", {"form": form})

    form = UserModelForm(data=request.POST)
    if not form.is_valid():
        return render(request, "form.html", {"form": form})

    form.save()
    return redirect(to="user")


def user_edit(request, id):
    instance = models.User.objects.filter(id=id).first()
    if request.method == "GET":
        form = UserModelForm(instance=instance)
        return render(request, "form.html", {"form": form})
    form = UserModelForm(instance=instance, data=request.POST)
    if not form.is_valid():
        return render(request, "user.html", {"form": form})
    form.save()
    return redirect(to="user")


def user_del(request, id):
    models.User.objects.filter(id=id).delete()
    return redirect(to="user")


def order(request):
    return HttpResponse("OK")


def order_add(request):
    return HttpResponse("OK")


def order_edit(request, id):
    return HttpResponse("OK")


def order_del(request, id):
    return HttpResponse("OK")


class MenuModelForm(ModelForm):
    class Meta:
        model = models.Menu
        fields = "__all__"


def menu(request):
    if request.method == "GET":
        queryset = models.Menu.objects.all()
        return render(request, "menu.html", {"queryset": queryset})
    return HttpResponse("OK")


def menu_add(request):
    if request.method == "GET":
        form = MenuModelForm()
        return render(request, "form.html", {"form": form})

    form = MenuModelForm(data=request.POST)
    if not form.is_valid():
        return render(request, "form.html", {"form": form})

    form.save()
    return redirect(to="menu")


def menu_edit(request, id):
    instance = models.Menu.objects.filter(id=id).first()
    if request.method == "GET":
        form = MenuModelForm(instance=instance)
        return render(request, "form.html", {"form": form})
    form = MenuModelForm(instance=instance, data=request.POST)
    if not form.is_valid():
        return render(request, "menu.html", {"form": form})
    form.save()
    return redirect(to="menu")


def menu_del(request, id):
    models.Menu.objects.filter(id=id).delete()
    return redirect(to="menu")

layout.html

{% load menu %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body {
            margin: 0;
        }
        .pg-header {
            height: 48px;
            background-color: aquamarine;
        }

        .pg-body > .menu {
            position: absolute;
            left: 0;
            top: 48px;
            bottom: 0;
            width: 220px;
            background-color: #ddd;
        }

        .pg-body > .body {
            position: absolute;
            left: 220px;
            top: 48px;
            bottom: 0;
            right: 0;
        }
    </style>
</head>
<body>

<div class="pg-header"></div>
<div class="pg-body">
    <div class="menu">
        {% menu request %}
    </div>
    <div class="body">
        {% block body %}
        {% endblock %}
    </div>
</div>

</body>
</html>

computer.html

{% extends "layout.html" %}
{% load permission %}

{% block body %}

    {% if request|has_permission:"computer_add" %}
        <a href="{% url "computer_add" %}">新增</a>
    {% endif %}

    {% if request|has_permission:"computer_edit" %}
        <a href="{% url "computer_edit" id=1 %}">编辑</a>
    {% endif %}

    {% if request|has_permission:"computer_del" %}
        <a href="{% url "computer_del" id=1 %}">删除</a>
    {% endif %}

{% endblock %}'

form.html

{% extends "layout.html" %}
{% load permission %}

{% block body %}
    <form method="post" novalidate>
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">提交</button>
    </form>

{% endblock %}

home.html

{% extends "layout.html" %}
{% load permission %}

{% block body %}
    <h1>欢迎登录</h1>
{% endblock %}

menu.html

{% extends "layout.html" %}
{% load permission %}

{% block body %}

    <a href="{% url 'menu_add' %}">新增</a>

    <table border="1">
        <thead>
        <tr>
            <th>ID</th>
            <th>菜单名称</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for item in queryset %}
            <tr>
                <td>{{ item.id }}</td>
                <td>{{ item.title }}</td>
                <td>
                    <a href="{% url 'menu_edit' id=item.id %}">编辑</a>
                    <a href="{% url 'menu_del' id=item.id %}">删除</a>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

{% endblock %}

permission.html

{% extends "layout.html" %}
{% load permission %}

{% block body %}

<form method="post">
    {% csrf_token %}
    <input type="submit" value="同步">
</form>

<table border="1">
    <thead>
    <tr>
        <th>ID</th>
        <th>名称</th>
        <th>CODE</th>
    </tr>
    </thead>
    <tbody>
    {% for item in queryset %}
        <tr>
            <td>{{ item.id }}</td>
            <td>{{ item.name }}</td>
            <td>{{ item.code }}</td>
        </tr>
    {% endfor %}
    </tbody>
</table>

{% endblock %}

role.html

{% extends "layout.html" %}
{% load permission %}

{% block body %}

    <a href="{% url 'role_add' %}">新增</a>
    <table border="1">
        <thead>
        <tr>
            <th>ID</th>
            <th>名称</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for row in queryset %}
            <tr>
                <td>{{ row.id }}</td>
                <td>{{ row.name }}</td>
                <td>
                    <a href="{% url 'role_edit' id=row.id %}">编辑</a>
                    <a href="{% url 'role_del' id=row.id %}">删除</a>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

{% endblock %}

user.html

{% extends "layout.html" %}
{% load permission %}

{% block body %}

    <a href="{% url 'user_add' %}">新增</a>
    <table border="1">
        <thead>
        <tr>
            <th>用户名</th>
            <th>密码</th>
            <th>超级管理员</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for row in queryset %}
            <tr>
                <td>{{ row.username }}</td>
                <td>{{ row.password }}</td>
                <td>{{ row.is_super }}</td>
                <td>
                    <a href="{% url 'user_edit' id=row.id %}">编辑</a>
                    <a href="{% url 'user_del' id=row.id %}">删除</a>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

{% endblock %}

templatetags/menu.py

from django.template import Library

register = Library()


@register.inclusion_tag("include/menu.html")
def menu(request):
    menu_dict = {}
    # 1、获取当前用户的所有菜单
    # print(request.menu_list)
    # 2、获取当前用户的所有权限
    # print(request.permission_dict)
    # 3、将菜单中当前用户无权限的,进行剔除
    for item in request.menu_list:
        id, title, name, code = item['id'], item['title'], item['permissions__name'], item['permissions__code']
        menu_dict.setdefault(id, {"title": title, "children": []})

        if request.user_dict['is_super']:
            menu_dict[id]['children'].append({"name": name, "code": code})
            continue

        if code not in request.permission_dict:
            continue
        menu_dict[id]['children'].append({"name": name, "code": code})

    print(menu_dict)
    return {"menu_dict": menu_dict}

templates/include/menu.html

{% for item in menu_dict.values %}
    <div>{{ item.title }}</div>
    {% if item.children %}
        {% for child in item.children %}
            <a style="display: block" href="{% url child.code %}">{{ child.name }}</a>
        {% endfor %}
    {% endif %}
{% endfor %}

utils/md.py

from django.contrib.auth.middleware import MiddlewareMixin
from django.urls import reverse
from django.shortcuts import redirect, HttpResponse
from www import models


class AuthMiddleware(MiddlewareMixin):
    def process_request(self, request):
        if request.path_info in [reverse("login")]:
            return

        user_dict = request.session.get("user_session_key")
        if not user_dict:
            return redirect("login")

        request.user_dict = user_dict


class PermissionMiddleware(MiddlewareMixin):
    def process_view(self, request, callback, *args, **kwargs):
        if request.path_info in [reverse("login")]:
            return

        if request.user_dict["is_super"]:
            menus = models.Menu.objects.all().values("id", "title", "permissions__name", "permissions__code")
            request.menu_list = menus
            return

        # 用户访问的rl
        url_name = request.resolver_match.url_name
        print("PermissionMiddleware中间件: ", url_name)

        # 用户对象
        user_object = models.User.objects.filter(id=request.user_dict['id']).first()

        # 获取当前用户的所有菜单
        menus = models.Menu.objects.filter(user=user_object).values("id", "title", "permissions__name", "permissions__code")
        request.menu_list = menus

        # 用户所有的角色,角色对应的权限
        user_per_list = user_object.roles.all().values("permissions__code", "permissions__name")
        permission_dict = {item["permissions__code"]: item["permissions__name"] for item in user_per_list}
        print("PermissionMiddleware中间件: ", permission_dict)

        request.permission_dict = permission_dict

        if url_name in permission_dict:
            return

        return HttpResponse("无权访问")

知识点巩固:
html用法:width、height、{% url “user_add” %}、母版的引用、
model的跨表查询,__str__用法,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值