Django ModelForm如何自动填充当前用户并过滤收件人选项
Django 站内消息功能优化实现方案
你需要修改表单、视图两个核心部分,即可实现发件人自动填充、收件人排除当前用户的需求,具体修改如下:
1. 修改表单文件 Forms.py
核心改动:
- 移除用户可编辑的
zender(发件人)字段,避免前端手动选择 - 重写表单初始化方法,接收当前登录用户参数,过滤收件人下拉选项
- 增加字段校验逻辑,拦截恶意构造的自发自收请求
class Mailsythemform(forms.ModelForm): class Meta: model = Mailsysthem # 移除zender字段,该字段由后端自动赋值 fields = ['ontvanger', 'subject', 'text'] def __init__(self, *args, **kwargs): # 提取传入的当前用户参数,避免传给父类表单报错 current_user = kwargs.pop('current_user', None) super().__init__(*args, **kwargs) self.current_user = current_user if current_user: # 收件人下拉列表排除当前登录用户 self.fields['ontvanger'].queryset = CustomUser.objects.exclude(id=current_user.id) def clean_ontvanger(self): # 额外校验层,防止恶意构造请求给自己发消息 receiver = self.cleaned_data.get('ontvanger') if self.current_user and receiver.id == self.current_user.id: raise forms.ValidationError("不允许选择自己作为收件人") return receiver
2. 修改视图文件 views.py
核心改动:
- 修复原代码缩进错误(原代码表单校验逻辑写在了POST请求判断外,GET请求会触发不必要的校验报错)
- 实例化表单时传入当前登录用户参数
- 表单校验通过后,自动给发件人字段赋值为当前登录用户,再存入数据库
def mailEMployee(request): # 未登录用户跳转登录页,如果你配置了全局登录校验可删除这段 if not request.user.is_authenticated: return redirect('login') # 查询当前用户的收件、发件记录,可根据你的业务加软删除过滤 received_mails = Mailsysthem.objects.filter(ontvanger=request.user, solftdelete=False) sent_mails = Mailsysthem.objects.filter(zender=request.user, solftdelete=False) if request.method == 'POST': # 传入当前用户参数初始化表单 form = Mailsythemform(request.POST, request.FILES, current_user=request.user) if form.is_valid(): # 先不写入数据库,补全发件人字段 mail_obj = form.save(commit=False) mail_obj.zender = request.user mail_obj.save() return redirect('mail') else: # GET请求初始化空表单,同样传入当前用户 form = Mailsythemform(current_user=request.user) context = { 'form': form, 'receiver': received_mails, # 注意原代码这里sender.all写法错误,QuerySet调用all需要加括号 'sender': sent_mails.all, 'mail': received_mails, # 原代码中查询user的逻辑冗余,request.user本身就是当前用户实例,可直接在模板使用 } return render(request, 'emp/mail.html', context)
补充说明
- 模板部分不需要额外改动,渲染表单时只会显示收件人、主题、正文三个输入项,发件人字段完全由后端自动填充,用户无法篡改
- 如果你需要给发件人设置初始值但保留字段只读,也可以不把
zender从fields里移除,而是在初始化时设置self.fields['zender'].initial = current_user,同时加self.fields['zender'].disabled = True,但直接移除字段的方式安全性更高 - 原代码中
CustomUser.objects.filter(email=request.user)逻辑有误,request.user是用户对象不是邮箱字符串,这个查询完全多余,直接使用request.user即可获取当前登录用户信息
内容的提问来源于stack exchange,提问作者UGC61
相关产品推荐
相关产品推荐

