You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中实现学校管理员仅查看自身创建的师生账号

实现学校管理员仅查看自身创建的师生账号

问题背景

我正在开发一款学校管理系统,学校注册后成为管理员,可创建教职工(Staff)与学生(Student)账号,师生能登录系统。核心需求是:多学校注册场景下,每个学校管理员仅能查看自身创建的教职工和学生账号。

目前已完成不同用户类型账号的创建,学校管理员可登录并创建师生账号,师生也能正常登录,但所有管理员都能查看全校师生,需解决该权限隔离问题。

现有代码如下:

【accounts/models.py】自定义用户模型

class CustomUser(AbstractUser):
    USER_TYPE = ((1, "school"), (2, "Staff"), (3, "Student"))
    GENDER = [("M", "Male"), ("F", "Female")]

    username = None  # Removed username, using email instead
    email = models.EmailField(unique=True)
    user_type = models.CharField(default=1, choices=USER_TYPE, max_length=1)
    gender = models.CharField(max_length=1, choices=GENDER)
    address = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []
    objects = CustomUserManager()

    def __str__(self):
        return self.last_name + ", " + self.first_name


# The School
class Admin(models.Model):
    admin = models.OneToOneField(CustomUser, on_delete=models.CASCADE)

    def __str__(self):
        return str(self.admin.email)

# staff
class Staff(models.Model):
    admin = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
    def __str__(self):
        return str(self.admin.email)



# students
class Student(models.Model):
    admin = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
    def __str__(self):
        return str(self.admin.email)

【school/views.py】添加教职工的视图

def add_staff(request):
    form = StaffForm(request.POST or None, request.FILES or None)
    context = {'form': form, 'page_title': 'Add  Staff'}
    if request.method == 'POST':
        if form.is_valid():
            first_name = form.cleaned_data.get('first_name')
            last_name = form.cleaned_data.get('last_name')
            address = form.cleaned_data.get('address')
            email = form.cleaned_data.get('email')
            gender = form.cleaned_data.get('gender')
            password = form.cleaned_data.get('password')
        
            try:
                user = CustomUser.objects.create_user(
                    email=email, password=password, user_type=2, first_name=first_name, last_name=last_name)
                user.gender = gender
                user.address = address
                user.save()
                messages.success(request, " Staff Successfully Added")
                return redirect('school_home')

            except Exception as e:
                messages.error(request, "Could Not Add " + str(e))
        else:
            messages.error(request, "Please fulfil all requirements")

    return render(request, 'add_staff_template.html', context)

【school/views.py】添加学生的视图

def add_student(request):
    form = StudentForm(request.POST or None, request.FILES or None)
    context = {'form': form, 'page_title': 'Add  Student'}
    if request.method == 'POST':
        if form.is_valid():
            first_name = form.cleaned_data.get('first_name')
            last_name = form.cleaned_data.get('last_name')
            address = form.cleaned_data.get('address')
            email = form.cleaned_data.get('email')
            gender = form.cleaned_data.get('gender')
            password = form.cleaned_data.get('password')
        
            try:
                user = CustomUser.objects.create_user(
                    email=email, password=password, user_type=3, first_name=first_name, last_name=last_name)
                user.gender = gender
                user.address = address
                user.save()
                messages.success(request, " Student Successfully Added")
                return redirect('school_home')

            except Exception as e:
                messages.error(request, "Could Not Add " + str(e))
        else:
            messages.error(request, "Please fulfil all requirements")

    return render(request, 'add_student_template.html', context)

【school/views.py】展示师生的视图

def school_home (request):
    total_staff = Staff.objects.all().count()
    total_students = Student.objects.all().count()
    # listing the students and staffs
    students = CustomUser.objects.filter(user_type=3)
    staffs = CustomUser.objects.filter(user_type=2)


    
    context = {
        'total_staff': total_staff,
        'total_students': total_students,  
        'students': students,      
        'staffs': staffs,       

    }
    return render(request, 'school_home.html', context)

解决方案

要实现权限隔离,核心是给每个师生账号绑定创建它的学校管理员,然后在查询时只返回当前管理员绑定的账号,具体步骤如下:

1. 修改模型,添加关联字段

在CustomUser模型中新增外键字段,记录创建该账号的学校管理员:

class CustomUser(AbstractUser):
    # ... 原有字段
    # 添加关联字段:记录创建该账号的学校管理员
    created_by = models.ForeignKey(
        'Admin', 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True,
        related_name='created_users'
    )
    # ... 原有字段

说明:学校管理员自身的账号created_by可设为null,因为是注册生成的。

2. 修改添加师生的视图,绑定创建者

在创建Staff和Student账号时,将当前登录的学校管理员赋值给created_by字段:

修改add_staff函数

def add_staff(request):
    form = StaffForm(request.POST or None, request.FILES or None)
    context = {'form': form, 'page_title': 'Add Staff'}
    if request.method == 'POST':
        if form.is_valid():
            # ... 原有字段获取逻辑
            try:
                # 获取当前登录的学校管理员
                current_admin = Admin.objects.get(admin=request.user)
                user = CustomUser.objects.create_user(
                    email=email, password=password, user_type=2, first_name=first_name, last_name=last_name)
                user.gender = gender
                user.address = address
                # 绑定创建者
                user.created_by = current_admin
                user.save()
                messages.success(request, "Staff Successfully Added")
                return redirect('school_home')

            except Exception as e:
                messages.error(request, "Could Not Add " + str(e))
        else:
            messages.error(request, "Please fulfil all requirements")

    return render(request, 'add_staff_template.html', context)

修改add_student函数

def add_student(request):
    form = StudentForm(request.POST or None, request.FILES or None)
    context = {'form': form, 'page_title': 'Add Student'}
    if request.method == 'POST':
        if form.is_valid():
            # ... 原有字段获取逻辑
            try:
                # 获取当前登录的学校管理员
                current_admin = Admin.objects.get(admin=request.user)
                user = CustomUser.objects.create_user(
                    email=email, password=password, user_type=3, first_name=first_name, last_name=last_name)
                user.gender = gender
                user.address = address
                # 绑定创建者
                user.created_by = current_admin
                user.save()
                messages.success(request, "Student Successfully Added")
                return redirect('school_home')

            except Exception as e:
                messages.error(request, "Could Not Add " + str(e))
        else:
            messages.error(request, "Please fulfil all requirements")

    return render(request, 'add_student_template.html', context)

3. 修改展示视图,过滤当前管理员的账号

在school_home视图中,只查询当前管理员创建的Staff和Student:

def school_home(request):
    # 获取当前登录的学校管理员
    current_admin = Admin.objects.get(admin=request.user)
    # 过滤当前管理员创建的教职工和学生
    total_staff = CustomUser.objects.filter(user_type=2, created_by=current_admin).count()
    total_students = CustomUser.objects.filter(user_type=3, created_by=current_admin).count()
    students = CustomUser.objects.filter(user_type=3, created_by=current_admin)
    staffs = CustomUser.objects.filter(user_type=2, created_by=current_admin)

    context = {
        'total_staff': total_staff,
        'total_students': total_students,  
        'students': students,      
        'staffs': staffs,       
    }
    return render(request, 'school_home.html', context)

4. 执行数据库迁移

修改模型后,运行以下命令更新数据库:

python manage.py makemigrations
python manage.py migrate

额外优化建议

  • 添加权限验证:使用@user_passes_test装饰器确保只有学校管理员才能访问相关页面:
    from django.contrib.auth.decorators import user_passes_test
    
    def is_school_admin(user):
        return user.user_type == '1'
    
    @user_passes_test(is_school_admin)
    def add_staff(request):
        # ... 原有代码
    
  • 历史数据处理:如果存在未绑定创建者的历史账号,可批量更新created_by字段,关联到对应的管理员。

内容的提问来源于stack exchange,提问作者Joseph Ayemlo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:04:55