在Django项目里,我们常需要在表单中记录提交数据的用户,例如留言、订单或工单的创建人。为了避免用户伪造他人身份,同时也要减少手动选择用户的麻烦,最合理的做法是在后端自动填充用户字段,并在前端将其设为不可编辑状态。

一、定义模型和表单
先创建一个简单的业务模型,其中包含指向用户的外键字段:
from django.db import models
from django.contrib.auth.models import User
class Task(models.Model):
title = models.CharField(max_length=100, verbose_name='任务标题')
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='创建人')
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
接着使用ModelForm生成表单类,并在初始化时接收当前用户:
from django import forms
from .models import Task
class TaskForm(forms.ModelForm):
class Meta:
model = Task
fields = ['title', 'user']
def __init__(self, *args, **kwargs):
# 从关键字参数中取出当前登录用户
self.current_user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
if self.current_user:
# 自动填充用户字段
self.fields['user'].initial = self.current_user
# 禁用该字段,防止前端修改
self.fields['user'].disabled = True
self.fields['user'].widget.attrs['readonly'] = True
二、在视图中传递用户
在基于函数的视图里,把request.user传给表单:
from django.shortcuts import render, redirect
from .forms import TaskForm
def create_task(request):
if request.method == 'POST':
form = TaskForm(request.POST, user=request.user)
if form.is_valid():
form.save()
return redirect('task_list')
else:
form = TaskForm(user=request.user)
return render(request, 'create_task.html', {'form': form})
为什么用 disabled 而不是只靠前端 readonly
如果只设置HTML的readonly属性,用户仍可通过修改请求包提交user值。Django的disabled会在清洗数据时直接忽略该字段的提交内容,使用initial中的值,更加安全。
三、模板渲染示例
模板中正常渲染表单即可,被禁用的用户字段会显示为不可选:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">提交</button>
</form>
四、常见问题
- 如果用户字段是必填但禁用,确保initial已赋值,否则校验会报错。
- 在管理员后台也可通过
exclude配合save_model实现类似逻辑。 - 使用
disabled后,编辑已存在对象时也会忽略POST中的user,自动沿用原值。
小结:通过重写ModelForm的__init__方法并配合disabled属性,可以优雅地实现用户字段自动填充与禁用,既提升体验又保障数据安全。