本文介绍在 django 表单集(formset)中安全禁用非编辑字段的正确方法:使用 `form.fields['field'].disabled = true` 替代 html `disabled` 属性,确保字段既不可编辑、又参与验证与保存,避免因前端禁用导致数据丢失或 csrf 绕过风险。
在 Django 开发中,常需在表格界面中混合展示“可编辑字段”与“只读字段”(如 department 字段仅用于展示、不应被用户修改)。初学者易误用 HTML 的 disabled="True" 属性(如 widgets={'department': Select(attrs={'disabled': 'True'})}),但这会导致严重问题:
应将禁用逻辑移至 Python 层——在 ModelForm.__init__() 中显式设置字段 disabled=True。这不仅禁用前端交互,更关键的是:
# forms.py
class OrderCloseForm(forms.ModelForm):
class Meta:
model = Order
fields = ('type_car', 'department', 'car', ...) # 明确列出所有需呈现的字段
widgets = {
'car': forms.Select(attrs={'style': 'width: 100%'}),
'department': forms.Select(attrs={'style': 'width: 100%'}), # 移除 disabled 属性!
# 其他字段...
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# ✅ 关键:服务端禁用,安全且可靠
self.fields['department'].disabled = True
# 如需禁用多个字段,可链式设置:
# self.fields['car'].disabled = True
# self.fields['order_date'].disabled = True原视图中存在重复初始化 formset、未处理 request.FILES、缺少重定向等问题。修正后如下:
# views.py
def orders_list(request, year, month, day):
orders = Order.objects.filter(
order_date__year=year,
order_date__month=month,
order_date__day=day
)
if request.method == 'POST':
formset = OrderCloseFormSet(
request.POST,
request.FILES, # 若含文件上传,务必传入
queryset=orders,
prefix='order'
)
if formset.is_valid():
formset.save() # ✅ 直接 save(),等价于 save(commit=True)
# ✅ PRG 模式:成功后重定向,防止重复提交
return redirect('orders:orders_list', year=year, month=month, day=day)
else:
# ✅ GET 请求时才初始化空 formset
formset = OrderCloseFormSet(queryset=orders, prefix='order')
context = {'orders': orders, 'formset': formset}
return render(request, 'orders/orders_list.html', context){% for form in formset %}
{% for field in form.visible_fields %}
{{ field|addclass:'input-box input-select' }}
{% endfor %}
{% endfor %}
| 方式 | 是否提交数据 | 是否校验 | 是否可篡改 | 推荐度 |
|---|---|---|---|---|
| widgets={'attr':{'disabled':'True'}} | ❌ 否 | ❌(因无数据) | ✅ 是(纯前端) | ❌ 不推荐 |
| self.fields['x'].disabled = True | ✅ 是(自动隐藏域) | ✅ 跳过验证 | ❌ 否(服务端控制) | ✅ 强烈推荐 |
通过服务端禁用字段,你既能实现清晰的 UI 分层(编辑/只读),又能保证数据完整性、安全性和表单逻辑的健壮性。这是 Django 表单集开发中的最佳实践。