如何在Django 2中实现多级分层管理员权限体系?
Hey there! Let's break down how to implement this multi-tier admin system in Django 2 step by step. Based on your requirements, we'll focus on model structure, permission mapping, access control logic, and role-specific workflows.
一、核心模型设计
First, we'll extend Django's user system to support custom roles and company associations. Using AbstractUser is the cleanest approach for Django 2.
1. 自定义用户模型
from django.contrib.auth.models import AbstractUser from django.db import models class CustomUser(AbstractUser): ROLE_CHOICES = ( ('superadmin_a', 'Superadmin_A'), ('admin_a', 'Admin_A'), ('superadmin_b', 'Superadmin_B'), ('admin_b', 'Admin_B'), ) role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='admin_b') # Link B-level admins to their parent company company = models.ForeignKey('Company', on_delete=models.SET_NULL, null=True, blank=True, related_name='staff') def __str__(self): return f"{self.username} ({self.get_role_display()})"
2. 公司模型
class Company(models.Model): name = models.CharField(max_length=100, unique=True) created_by = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True, related_name='created_companies') created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return self.name
Don't forget to update settings.py to use your custom user model:
AUTH_USER_MODEL = 'your_app_name.CustomUser'
二、权限逻辑封装
We'll create reusable helper functions and decorators to simplify permission checks across views. This keeps your code DRY and easy to maintain.
from django.core.exceptions import PermissionDenied from django.http import HttpResponseForbidden # Core permission checks def is_superadmin_a(user): return user.role == 'superadmin_a' def is_admin_a(user): return user.role == 'admin_a' or is_superadmin_a(user) def is_superadmin_b(user): return user.role == 'superadmin_b' and user.company is not None def is_admin_b(user): return user.role == 'admin_b' and user.company is not None def can_manage_company_content(user): return is_superadmin_b(user) or is_admin_b(user) # View decorators def require_superadmin_a(view_func): def wrapped(request, *args, **kwargs): if not is_superadmin_a(request.user): return HttpResponseForbidden("You don't have permission to access this page.") return view_func(request, *args, **kwargs) return wrapped def require_admin_a(view_func): def wrapped(request, *args, **kwargs): if not is_admin_a(request.user): return HttpResponseForbidden("You don't have permission to access this page.") return view_func(request, *args, **kwargs) return wrapped
三、角色-specific 视图实现
Now let's build views for each role's allowed actions.
1. Superadmin_A 操作
from django.views.generic import CreateView, ListView from .models import CustomUser, Company @require_superadmin_a class SuperadminACreateView(CreateView): model = CustomUser fields = ['username', 'email', 'password', 'role'] success_url = '/site-dashboard/' def form_valid(self, form): # Restrict to creating only Superadmin_A or Admin_A if form.cleaned_data['role'] not in ['superadmin_a', 'admin_a']: form.add_error('role', "You can only create Superadmin_A or Admin_A accounts.") return self.form_invalid(form) # Set password properly (don't store plain text) user = form.save(commit=False) user.set_password(form.cleaned_data['password']) user.save() return super().form_valid(form) @require_superadmin_a class CompanyWithSuperadminBCreateView(CreateView): model = Company fields = ['name'] success_url = '/companies/' def form_valid(self, form): company = form.save(commit=False) company.created_by = self.request.user company.save() # Auto-create a Superadmin_B for the new company (optional) superadmin_b = CustomUser.objects.create( username=f"{company.name}_superadmin", email=f"superadmin_{company.name}@example.com", role='superadmin_b', company=company ) superadmin_b.set_password('temp1234') # Send a password reset email instead in production superadmin_b.save() return super().form_valid(form)
2. Admin_A 操作
@require_admin_a class CompanyCreateView(CreateView): model = Company fields = ['name'] success_url = '/companies/' def form_valid(self, form): company = form.save(commit=False) company.created_by = self.request.user company.save() return super().form_valid(form)
3. Superadmin_B & Admin_B 操作
from django.views.generic.edit import UpdateView from .models import Article, Member # Superadmin_B creates Admin_B @require_superadmin_b class AdminBCreateView(CreateView): model = CustomUser fields = ['username', 'email', 'password'] success_url = '/company-dashboard/' def form_valid(self, form): user = form.save(commit=False) user.role = 'admin_b' user.company = self.request.user.company user.set_password(form.cleaned_data['password']) user.save() return super().form_valid(form) # Manage company articles (accessible to both B-level roles) class ArticleCreateView(CreateView): model = Article fields = ['title', 'content'] def dispatch(self, request, *args, **kwargs): if not can_manage_company_content(request.user): return HttpResponseForbidden("You don't have permission to manage company content.") return super().dispatch(request, *args, **kwargs) def form_valid(self, form): article = form.save(commit=False) article.company = self.request.user.company article.created_by = self.request.user article.save() return super().form_valid(form)
四、模板层权限控制
Show/hide UI elements based on the user's role in your templates:
{% if user.role == 'superadmin_a' %} <div class="admin-menu"> <a href="{% url 'create_superadmin_a' %}">Create Superadmin_A</a> <a href="{% url 'create_admin_a' %}">Create Admin_A</a> <a href="{% url 'create_company_with_superadmin_b' %}">Create Company + Superadmin_B</a> </div> {% elif user.role == 'admin_a' %} <a href="{% url 'create_company' %}">Create New Company</a> {% elif user.role in ['superadmin_b', 'admin_b'] %} <div class="company-menu"> {% if user.role == 'superadmin_b' %} <a href="{% url 'create_admin_b' %}">Create Admin_B</a> {% endif %} <a href="{% url 'create_article' %}">Publish Article</a> <a href="{% url 'manage_members' %}">Manage Company Members</a> </div> {% endif %}
五、B级管理员登录限制
Ensure B-level admins can only access their own company's resources. Add a post-login redirect and enforce company ownership checks:
- Update
settings.py:
LOGIN_REDIRECT_URL = 'dashboard_redirect'
- Create the redirect view:
from django.shortcuts import redirect def dashboard_redirect(request): user = request.user if user.role in ['superadmin_b', 'admin_b']: return redirect('company_dashboard', company_id=user.company.id) return redirect('site_dashboard')
- Enforce company ownership in company views:
class CompanyDashboardView(DetailView): model = Company template_name = 'company_dashboard.html' def get_object(self, queryset=None): obj = super().get_object(queryset) if self.request.user.company != obj: return HttpResponseForbidden("You can only access your own company's dashboard.") return obj
六、测试建议
- Create test users for each role and verify they can only perform allowed actions
- Write unit tests for permission helper functions to catch edge cases (e.g., Superadmin_B trying to access another company's content)
- Test password reset flows for auto-created Superadmin_B accounts
内容的提问来源于stack exchange,提问作者Kirsten Phukon

