Django使用StreamingHttpResponse实现人脸考勤时的页面跳转问题
问题根因
- 你在视频流生成函数
getFace()中调用takeAttendance()拿到的render/redirect返回值没有传递给用户的页面请求,自然不会触发页面跳转。getFace()的唯一作用是给StreamingHttpResponse持续输出视频帧,当前/videoFeed请求和首页的页面请求是完全独立的两个请求,你手动修改request属性的操作没有任何作用。 - 你的全局摄像头实例
vs只要服务端不重启就会一直运行,天然满足跳转后不需要重启摄像头的需求。
解决方案
后端修改
- 新增全局变量存储考勤识别结果,修改
getFace逻辑,识别成功后只存结果不处理跳转:
from django.http import JsonResponse # 原有全局变量不变,新增以下变量 attendance_result = None def getFace(request): global vs,outputFrame,lock,foundFace, attendance_result known_face_names,known_face_encodings = getFiles() face_location = [] face_encoding = [] while foundFace==False: check,frame = vs.read() small_frame = cv2.resize(frame,(0,0),fx=0.5,fy=0.5) face_roi = small_frame[:,:,::-1] face_location = face_recognition.face_locations(face_roi) face_encoding = face_recognition.face_encodings(face_roi,face_location) face_names = [] names=[] for encoding in face_encoding: matches = face_recognition.compare_faces(known_face_encodings,np.array(encoding),tolerance=0.6) distances = face_recognition.face_distance(known_face_encodings,encoding) best_match_index = np.argmin(distances) if matches[best_match_index]: name = known_face_names[best_match_index] face_names.append(name) if name not in names: names.append(name) with lock: (flag,encodedImg) = cv2.imencode(".jpg",frame) if len(names)!=0: foundFace=True if foundFace==True: # 识别成功后存储考勤结果,不处理跳转 if user_id in names: attendance = Attendance(user_ID = str(user_id), date_in = date.today(), time_in = datetime.now()) attendance.save() attendance_result = { "status": "success", "user_id": str(user_id), "time_in": str(datetime.now()) } else: attendance_result = {"status": "failed"} foundFace=False yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + bytearray(encodedImg) + b'\r\n')
- 新增考勤结果查询接口:
def get_attendance_result(request): global attendance_result res = attendance_result attendance_result = None # 查询后清空结果,避免重复返回 return JsonResponse(res)
- 修改
takeAttendance接口,直接渲染考勤页:
def takeAttendance(request): context={} if request.method=='GET': user_id = request.GET.get('user_id') time_in = request.GET.get('time_in') # 也可根据user_id查询数据库最新的考勤记录 context={'attendance': {"user_ID": user_id, "time_in": time_in}} messages.success(request,'Check in successful') return render(request,'Attendance/attendance.html',context) else: return redirect('home')
urls.py新增路由:
urlpatterns=[ path('home/',views.home,name='home'), path('takeAttendance/',views.takeAttendance,name='takeAttendance'), path('videoFeed/',views.videoFeed,name='videoFeed'), path('getAttendanceResult/',views.get_attendance_result,name='get_attendance_result'), ]
前端修改
- 首页(摄像头页面)新增轮询逻辑,识别成功后自动跳转到考勤页:
// 每300ms查询一次考勤识别结果 setInterval(() => { fetch('/getAttendanceResult/') .then(res => res.json()) .then(data => { if(!data) return if(data.status === 'success') { // 跳转到考勤详情页,携带参数 window.location.href = `/takeAttendance/?user_id=${data.user_id}&time_in=${data.time_in}` } else { alert('打卡失败,未匹配到用户信息') } }) }, 300)
Attendance.html新增定时跳转逻辑,停留数秒后自动返回首页:
// 3秒后自动跳转回首页 setTimeout(() => { window.location.href = '/home/' }, 3000)
注意事项
- 原有代码中
vs = cv2.videoCapture(0)存在拼写错误,应为cv2.VideoCapture(0),否则会报错。 - 全局变量存储考勤结果的方案仅适合本地测试、单进程部署场景,如需上线多实例部署,可替换为Redis缓存存储识别结果。
内容的提问来源于stack exchange,提问作者biiiiiiii
相关产品推荐
相关产品推荐

