import datetime
import json
import openpyxl
from pathlib import Path
from io import BytesIO
from django.contrib.auth.hashers import make_password
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import ListView, CreateView, DeleteView, UpdateView
from django.contrib.auth.models import User
from django.db.models import Q
from grades.models import Grade
from students.models import Student
from utils.handle_excel import ReadExcel
from .forms import StudentForm
from utils.permissions import RoleRequiredMixin, role_required
# 权限类
class BaseStudentView(RoleRequiredMixin):
model = Student
context_object_name = 'students'
form_class = StudentForm
success_url = reverse_lazy('students_list')
allowed_roles = ['admin', 'teacher']
# Create your views here.
class StudentListView(BaseStudentView, ListView):
template_name = 'students/students_list.html'
paginate_by = 3
def get_queryset(self):
queryset = super().get_queryset()
grade_id = self.request.GET.get('grade')
search_content = self.request.GET.get('search')
if grade_id:
queryset = queryset.filter(grade__pk=grade_id)
if search_content:
queryset = queryset.filter(
Q(student_name=search_content) |
Q(student_number=search_content)
)
return queryset
def get_context_data(self):
context = super().get_context_data()
context['grades'] = Grade.objects.all().order_by('grade_number')
context['current_id'] = self.request.GET.get('grade', '')
return context
class StudentCreateView(BaseStudentView, CreateView):
template_name = 'students/students_form.html'
def form_valid(self, form): # 验证成功
# 接收字段
student_name = form.cleaned_data.get('student_name')
student_number = form.cleaned_data.get('student_number')
# 写入到auth_user表
username = student_name + "_" + student_number
password = student_number[-6:]
users = User.objects.filter(username=username)
if users.exists():
user = users.first
else:
user = User.objects.create_user(username=username, password=password)
# 写入到student表
form.instance.user = user
form.save()
return JsonResponse({
'status': 'success',
'messages': '操作成功'
}, status=200)
def form_invalid(self, form): # 验证失败
errors = form.errors.as_json()
return JsonResponse({
'status': 'fail',
'messages': errors
}, status=400)
class StudentUpdateView(BaseStudentView, UpdateView):
template_name = 'students/students_form.html'
def form_valid(self, form):
# 获取学生对象实例
student = form.save(commit=False)
# 检查是否修改了学号或姓名
if 'student_number' or 'student_name' in form.changed_data:
student.user.username = form.cleaned_data.get('student_name') + '_' + form.cleaned_data.get(
'student_number')
student.user.password = make_password(form.cleaned_data.get('student_number')[-6:])
student.user.save() # 保存更改的用户模型
# 保存student模型
student.save()
return JsonResponse({
'status': 'success',
'messages': '操作成功'
}, status=200)
def form_invalid(self, form):
errors = form.errors.as_json()
return JsonResponse({
'status': 'fail',
'messages': errors
}, status=400)
class StudentDeleteView(BaseStudentView, DeleteView):
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
try:
self.object.delete()
return JsonResponse({
'status': 'success',
'messages': '删除成功'
}, status=200)
except Exception as e:
return JsonResponse({
'status': 'fail',
'messages': '删除失败' + str(e)
}, status=400)
class StudentBulkDeleteView(BaseStudentView, DeleteView):
def post(self, request, *args, **kwargs):
selected_ids = request.POST.getlist('student_ids')
if not selected_ids:
return JsonResponse({
'status': 'fail',
'messages': '请选择要删除的学生'
})
self.object_list = self.get_queryset().filter(id__in=selected_ids)
try:
self.object_list.delete()
return JsonResponse({
'status': 'success',
'messages': '删除成功'
}, status=200)
except Exception as e:
return JsonResponse({
'status': 'fail',
'messages': '删除失败' + str(e)
}, status=400)
@role_required('admin', 'teacher')
def upload_students(request):
"""
上传学生信息
:param request:
:return:
"""
if request.method == 'POST':
file = request.FILES.get('excel_file')
if not file:
return JsonResponse({
'status': 'error',
'messages': '请上传excel文件'
}, status=400)
if Path(file.name).suffix.lower() != '.xlsx':
return JsonResponse({
'status': 'error',
'messages': '文件类型错误,请上传.xlsx格式的文件'
}, status=400)
read_excel = ReadExcel(file)
data = read_excel.get_data() # [[],[],[]]
if data[0] != ['班级', '姓名', '学号', '性别', '出生日期', '联系电话', '家庭住址']:
return JsonResponse({
'status': 'error',
'messages': 'excel格式错误'
}, status=400)
# 写入到数据库
for row in data[1:]:
grade, student_name, student_number, gender, birthday, contact_number, address = row
# 检查班级是否存在
student_number = str(student_number)
grade = Grade.objects.filter(grade_name=grade).first()
if not grade:
return JsonResponse({
'status': 'error',
'messages': f'{grade} 不存在'
}, status=400)
# 检测主要字段
if not student_name:
return JsonResponse({
'status': 'error',
'messages': '学生姓名不能为空'
}, status=400)
if not student_number or len(student_number) != 6:
return JsonResponse({
'status': 'error',
'messages': '学籍号不能为空,并且长度应为19位'
}, status=400)
# 检查日期格式
if not isinstance(birthday, datetime.datetime):
return JsonResponse({'status': 'error', 'messages': '出生日期格式错误'}, status=400)
# 判断学生信息是否存在
if Student.objects.filter(student_number=student_number).exists():
return JsonResponse({'status': 'error', 'messages': f'学号{student_number}已经存在'}, status=400)
# 写入数据库
try:
# 判断auth_user表中学生数据是否存在,不存在时,在auth_user表中创建用户
username = student_name + '_' + student_number # 拼接username
users = User.objects.filter(username=username)
if users.exists():