如何在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
相关产品推荐
相关产品推荐

