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

Django中出现'function' object has no attribute 'user'错误求解决

Django中间件报错:'function' object has no attribute 'user'

问题场景

基于AbstractUser扩展CustomUser模型实现Admin、NotesUser两种角色,配置了LoginCheckMiddleWare权限校验中间件后,访问登录页面触发错误:'function' object has no attribute 'user'。

相关代码

models.py

class CustomUser(AbstractUser):
    user_type_choices = ((1, "Admin"), (2, "NotesUser"))
    user_type = models.CharField(max_length=10, choices=user_type_choices, default=1)

class Admin(models.Model):
    user_id = models.OneToOneField(CustomUser, on_delete=models.CASCADE)

class NotesUser(models.Model):
    user_id = models.OneToOneField(CustomUser, on_delete=models.CASCADE)

@receiver(post_save, sender=CustomUser)
def create_user_profile(sender, created, instance, **kwargs):
    if created:
        if instance.user_type == 1:
            Admin.objects.create(user_id=instance)
        if instance.user_type == 2:
            NotesUser.objects.create(user_id=instance)

@receiver(post_save, sender=CustomUser)
def save_user_profile(sender, instance, **kwargs):
    if instance.user_type == 1:
        instance.admin.save()
    if instance.user_type == 2:
        instance.notesuser.save()

LoginCheckMiddleWare.py

from django.utils.deprecation import MiddlewareMixin
from django.urls import reverse
from django.http import HttpResponseRedirect, HttpResponse

class LoginCheckMiddleWare(MiddlewareMixin):
    def process_view(self, view_func, request, view_args, view_kwargs):
        modulename=view_func.__module__
        user = request.user
        if user.is_authenticated:
            if user.user_type == "1":
                if modulename == "todo_app.views" or modulename == "todo_app.AdminViews":
                    pass
                else:
                    return HttpResponseRedirect(reverse("admin_home"))
            elif user.user_type == "2":
                if modulename == "todo_app.UserViews" or modulename == "todo_app.views":
                    pass
                else:
                    return HttpResponseRedirect(reverse("user_home"))
            else:
                pass
                #return HttpResponseRedirect(reverse("log_in"))
        else:
            if request.path == reverse("log_in") or request.path == reverse("login_save") or modulename == "django.contrib.auth.views" or modulename == "todo_app.views":
                pass
            else:
                return HttpResponseRedirect(reverse("log_in"))

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',
    'todo_app.LoginCheckMiddleWare.LoginCheckMiddleWare',
]

错误原因

核心问题是中间件process_view方法的参数顺序写错了:
Django规定process_view的正确参数顺序为(self, request, view_func, view_args, view_kwargs),但你把view_func和request的位置写反了。这导致代码中user = request.user实际上是在访问视图函数对象的user属性,而视图函数没有该属性,因此抛出'function' object has no attribute 'user'错误。

解决步骤

1. 修正中间件参数顺序

将LoginCheckMiddleWare.py中的process_view方法参数调整为正确顺序:

def process_view(self, request, view_func, view_args, view_kwargs):

2. 额外修复与优化

  • 修复用户类型判断的类型不匹配:
    CustomUser中user_type是CharField,但信号处理代码中用整数1/2判断会导致逻辑失效,需要统一改为字符串判断:
    # 信号处理函数中修改判断条件
    if instance.user_type == "1":
        Admin.objects.create(user_id=instance)
    if instance.user_type == "2":
        NotesUser.objects.create(user_id=instance)
    
    或者直接把user_type_choices的键改为字符串,从根源避免类型混淆:
    user_type_choices = (("1", "Admin"), ("2", "NotesUser"))
    
  • 简化中间件逻辑:
    将允许访问的模块/路径整理为列表,用in判断替代多个or,提升代码可读性:
    # 修正后的完整中间件代码
    from django.utils.deprecation import MiddlewareMixin
    from django.urls import reverse
    from django.http import HttpResponseRedirect
    
    class LoginCheckMiddleWare(MiddlewareMixin):
        def process_view(self, request, view_func, view_args, view_kwargs):
            modulename = view_func.__module__
            user = request.user
            
            if user.is_authenticated:
                if user.user_type == "1":
                    allowed_modules = ["todo_app.views", "todo_app.AdminViews"]
                    if modulename not in allowed_modules:
                        return HttpResponseRedirect(reverse("admin_home"))
                elif user.user_type == "2":
                    allowed_modules = ["todo_app.UserViews", "todo_app.views"]
                    if modulename not in allowed_modules:
                        return HttpResponseRedirect(reverse("user_home"))
            else:
                allowed_paths = [reverse("log_in"), reverse("login_save")]
                allowed_modules = ["django.contrib.auth.views", "todo_app.views"]
                if request.path not in allowed_paths and modulename not in allowed_modules:
                    return HttpResponseRedirect(reverse("log_in"))
    

内容的提问来源于stack exchange,提问作者vishnu chandran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 07:36:34