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

Django中表单设为readonly时如何防止数据篡改?

解决Django只读表单字段被篡改提交的问题

核心问题很明确:前端的readonly只是UI层面的限制,任何人都能通过浏览器调试工具篡改字段值并提交,所以必须在后端做强制校验,前端的限制只是辅助提升用户体验。

一、后端强制校验(必须实现)

核心思路是:保留用户第一次提交的合法原始数据,第二次提交时直接使用原始数据,完全忽略前端传过来的只读字段值。

1. 存储原始数据到Session

第一次提交表单(步骤1)时,验证通过后把用户的合法数据存入Session:

def step1_submit(request):
    if request.method == 'POST':
        form = ProductForm(request.POST, request.FILES)
        if form.is_valid():
            # 将验证后的干净数据存入Session
            request.session['product_raw_data'] = form.cleaned_data
            return redirect('step2_page')
    # GET请求返回步骤1的表单页面
    return render(request, 'step1.html', {'form': ProductForm()})

2. 渲染步骤2的只读表单

从Session取出原始数据,初始化表单并设置只读属性:

def step2_page(request):
    raw_data = request.session.get('product_raw_data')
    if not raw_data:
        # 没有原始数据,直接跳回步骤1
        return redirect('step1_submit')
    
    # 用原始数据填充表单
    form = ProductForm(initial=raw_data)
    # 设置指定字段为只读
    form.fields['name'].widget.attrs['readonly'] = True
    # 其他需要只读的字段同理
    
    # 注意:这里要传表单对象,不是字符串!你之前的代码写错了
    return render(request, 'mypage.html', {'form_one_item': form})

3. 处理第二次提交时忽略篡改值

当用户提交步骤2的表单时,直接使用Session里的原始数据,完全不信任前端传来的只读字段:

def final_submit(request):
    raw_data = request.session.get('product_raw_data')
    if not raw_data:
        return redirect('step1_submit')
    
    # 处理业务逻辑,比如保存到数据库
    # 只读字段直接用raw_data里的值,不要用request.POST
    product = Product.objects.create(
        name=raw_data['name'],
        # 如果有其他非只读字段,可以从request.POST获取
        # price=request.POST.get('price')
    )
    
    # 清理Session里的临时数据
    del request.session['product_raw_data']
    return redirect('success_page')

二、前端增强限制(可选,提升体验)

虽然后端已经保证安全,前端可以做一些限制减少恶意篡改的可能性:

  • 给只读字段添加onfocus="this.blur()",阻止字段获得焦点:
{% for field in form_one_item %}
    {% if field.name == 'name' %}
        <input type="{{ field.field.widget.input_type }}"
               name="{{ field.name }}"
               value="{{ field.value }}"
               readonly
               onfocus="this.blur()">
    {% else %}
        {{ field }}
    {% endif %}
{% endfor %}
  • 用JS重置篡改后的字段值(虽然能被绕过,但增加门槛):
const readonlyInput = document.querySelector('input[name="name"]');
const originalValue = readonlyInput.value;
readonlyInput.addEventListener('input', () => {
    readonlyInput.value = originalValue;
});

三、修复你当前代码的错误

你现在的代码里把表单对象作为字符串'form_one_item'传给模板了,这会导致模板无法正确渲染表单,必须传变量本身:

# 错误写法:
return render(request, 'mypage.html', {'form_one_item':'form_one_item'})
# 正确写法:
return render(request, 'mypage.html', {'form_one_item': form_one_item})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 08:50:36