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

Django中ModelForm未显示当前用户选项问题排查

Django自定义User模型关联ModelForm后下拉框无选项问题排查

问题重现

自定义User模型并通过ForeignKey关联Test模型,使用ModelForm生成表单后,页面中researcher下拉框仅显示空选项,无用户可选。浏览器渲染的字段代码如下:

<select name="researcher" id="id_researcher">
<option value="" selected>---------</option>
</select>

核心问题及修复方案

1. 自定义User模型定义不完整(最关键原因)

你的User模型继承了AbstractBaseUser,但缺少Django用户模型必需的核心配置和字段:

  • 未定义USERNAME_FIELD(Django用来识别用户的唯一标识字段)
  • 缺少first_name、last_name、staff、admin这些被方法/属性引用的字段
  • 未实现自定义UserManager,导致Django无法正确创建和管理用户实例

修复后的models.py:

from django.db import models
from django.contrib.auth.models import (BaseUserManager, AbstractBaseUser)

class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('Users must have an email address')
        user = self.model(
            email=self.normalize_email(email),
            **extra_fields
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password=None, **extra_fields):
        extra_fields.setdefault('staff', True)
        extra_fields.setdefault('admin', True)
        return self.create_user(email, password, **extra_fields)

class User(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    first_name = models.CharField(max_length=30, blank=True)
    last_name = models.CharField(max_length=30, blank=True)
    staff = models.BooleanField(default=False)
    admin = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)

    objects = UserManager()

    # 指定唯一识别用户的字段
    USERNAME_FIELD = 'email'

    def get_full_name(self):
        return f"{self.first_name} {self.last_name}".strip()

    @property
    def is_staff(self):
        return self.staff

    @property
    def is_admin(self):
        return self.admin

2. 视图函数未正确处理GET请求且未预填充用户

原视图仅在POST请求时初始化表单,GET请求时form变量未定义会抛出异常;同时没有为表单预填充当前登录用户,也未限制下拉框的用户查询范围。

修复后的views.py:

from django.shortcuts import render
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from database.forms import TestForm
from database.models import User, Test

def index(request):
    return render(request, "database/index.html")

def test(request):
    form = TestForm()
    if request.method == "POST":
        form = TestForm(request.POST)
        if form.is_valid():
            # 保存时自动关联当前登录用户(可选,按需调整)
            test_instance = form.save(commit=False)
            if request.user.is_authenticated:
                test_instance.researcher = request.user
            test_instance.save()
            return HttpResponseRedirect(reverse('index'))  # 提交后跳转
    
    # 预填充当前登录用户(可选)
    if request.user.is_authenticated:
        form.initial['researcher'] = request.user.id
        # 限制下拉框仅显示当前用户(可选,按需调整)
        form.fields['researcher'].queryset = User.objects.filter(id=request.user.id)
    
    context={"form": form}
    return render(request, "database/test.html", context)

3. 表单字段查询集优化(可选)

如果需要自定义下拉框的用户范围,可以在TestForm中指定researcher字段的queryset:

优化后的forms.py:

from django.forms import ModelForm
from database.models import Test, User

class TestForm(ModelForm):
    class Meta:
        model = Test
        fields='__all__'

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 示例:仅显示活跃用户
        self.fields['researcher'].queryset = User.objects.filter(is_active=True)

额外验证步骤

  1. 执行数据库迁移:python manage.py makemigrations 和 python manage.py migrate,确保模型变更生效
  2. 创建测试用户:通过后台或createsuperuser命令创建用户实例,确保数据库中有User数据
  3. 确保用户已登录:只有登录状态下才能获取当前用户,否则无法预填充

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 19:25:17