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

Django中间件报错ContentNotRenderedError:讲师账号自动锁定功能异常

问题描述

我需要实现以下功能:

  • 管理员为讲师创建账号,默认密码为ou@123
  • 若讲师在设定时间(测试设为1分钟)内未修改密码,系统自动锁定账号(设置is_active=False)

我在middlewares和views中编写了处理代码,但运行时出现错误:

django.template.response.ContentNotRenderedError: The response content must be rendered before it can be accessed.
代码片段

middlewares.py

class PasswordChangeMiddleware(MiddlewareMixin):
    def process_request(self, request):
        if request.user.is_authenticated and request.user.is_staff:
            if not request.user.password_changed:
                if timezone.now() > request.user.date_joined + timedelta(minutes=1):
                    request.user.is_active = False
                    request.user.save()
        return None

    def process_response(self, request, response):
        if request.user.is_authenticated and not request.user.is_active:
            return Response({"message": "Account Locked"}, status=status.HTTP_403_FORBIDDEN)
        return response

settings.py

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'alumni.middlewares.PasswordChangeMiddleware',
]

views.py

class UserViewSet(viewsets.ViewSet, generics.CreateAPIView):
    queryset = User.objects.filter(is_active=True)
    serializer_class = serializers.UserSerializer
    parser_classes = [parsers.MultiPartParser, ]

    def get_permissions(self):
        if self.action in ['current_user', 'list_posts', 'get_posts', 'my_post', 'change_password']:
            return [permissions.IsAuthenticated()]
        elif self.action in ['create_lecturer']:
            return [permissions.IsAdminUser()]
        return [permissions.AllowAny()]

    @action(methods=['get', 'patch'], url_path='current-user', detail=False)
    def current_user(self, request):
        user = request.user
        if request.method.__eq__('PATCH'):
            for k, v in request.data.items():
                setattr(user, k, v)  # user.k = v
            user.save()
        return Response(serializers.UserSerializer(user).data)

    @action(methods=['post'], url_path='change-password', detail=False)
    def change_password(self, request):
        user = request.user
        current_password = request.data.get('current_password')
        new_password = request.data.get('new_password')
        confirm_password = request.data.get('confirm_password')

        if user.check_password(current_password):
            if new_password == confirm_password:
                user.set_password(new_password)
                user.password_changed = True
                user.save()
                return Response({"success": "Mật khẩu đã được thay đổi thành công!"})
            else:
                return Response({"error": "Xác nhận mật khẩu không khớp!"}, status=status.HTTP_400_BAD_REQUEST)

        return Response({"error": "Mật khẩu hiện tại không chính xác!"}, status=status.HTTP_400_BAD_REQUEST)

    @action(methods=['post'], url_path='create-lecturer', detail=False)
    def create_lecturer(self, request):
        data = request.data.copy()
        data['password'] = make_password('ou@123')
        data['is_staff'] = True

        serializer = self.serializer_class(data=data)
        if serializer.is_valid():
            user = serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
解决方案

错误原因

Django中间件的process_response方法要求返回Django原生的HttpResponse对象,但你返回了DRF的Response对象。DRF的Response需要经过DRF渲染器处理才能生成可访问的内容,直接在中间件返回会触发ContentNotRenderedError。

修改步骤

  1. 替换DRF Response为Django JsonResponse
    修改middlewares.py的process_response方法,导入JsonResponse并替换返回语句:

    from django.http import JsonResponse
    
    class PasswordChangeMiddleware(MiddlewareMixin):
        # 其他代码保持不变
        def process_response(self, request, response):
            if request.user.is_authenticated and not request.user.is_active:
                return JsonResponse({"message": "Account Locked"}, status=403)
            return response
    
  2. 优化账号锁定逻辑
    当前process_request中每次请求都会检查时间并更新用户状态,可能存在性能问题。可以改为:

    • 仅当用户尝试访问需要认证的接口时才触发检查
    • 或者使用Djangouser_logged_in信号,在用户登录时检查锁定状态
    • 更高效的方式是用定时任务(如Celery)批量处理过期未改密码的账号
  3. 处理已锁定用户的session
    账号被锁定后,需要清除用户session,避免用户通过旧session继续访问:

    def process_request(self, request):
        if request.user.is_authenticated and request.user.is_staff:
            if not request.user.password_changed:
                if timezone.now() > request.user.date_joined + timedelta(minutes=1):
                    request.user.is_active = False
                    request.user.save()
                    # 清除当前session
                    request.session.flush()
        return None
    

内容的提问来源于stack exchange,提问作者Trần Lê Lân

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 12:37:24