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

Django表单优化:用本地存储替代后端数据,实现无重载更新

无刷新实现可增删表单模块(基于本地存储)

我是Django初学者,开发了一个带表单的网页,表单包含预设值,用户需补充其余内容,其中教育经历、工作经验、技术技能属于可增删的多段模块,最终数据以JSON格式存储。当前点击添加/删除按钮时,前端能完成数据操作,但必须发送完整JSON至后端并重载页面才能更新显示。现需实现无需发送完整JSON到后端,通过本地存储完成表单更新且避免页面重载,技术栈为Django+HTML+JavaScript。

核心思路

  • 本地存储初始化:页面首次加载时,将后端传递的初始resume数据存入localStorage,作为前端数据的唯一数据源
  • 动态渲染模块:编写通用渲染函数,读取localStorage中的数据,动态生成对应的表单DOM元素
  • 增删操作仅修改本地存储:点击添加/删除按钮时,直接修改localStorage内的对应数据,再调用渲染函数更新页面,无需请求后端或重载
  • 最终统一提交:用户完成所有编辑后,一次性将localStorage中的完整数据提交至后端存储

修改后的代码实现

1. HTML部分(技术技能模块)

保留基础结构,将Django模板循环渲染改为JS动态生成:

<h2>Technical Skills</h2>
<!-- 动态渲染的技术技能模块插入容器 -->
<div id="tech-skills-container"></div>
<div id="techskill">
    <button type="button" onclick="addTechSkill()">Add Technical Skill</button>
</div>
<!-- Django安全传递初始数据 -->
{{ resume|json_script:"initial-resume-data" }}

2. JavaScript部分

初始化与渲染函数

// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
    // 从Django模板获取初始数据
    const initialResumeData = JSON.parse(document.getElementById('initial-resume-data').textContent);
    // 初始化本地存储(仅当无数据时)
    if (!localStorage.getItem('resumeData')) {
        localStorage.setItem('resumeData', JSON.stringify(initialResumeData));
    }
    // 首次渲染技术技能模块
    renderTechSkills();
});

// 渲染技术技能模块
function renderTechSkills() {
    const container = document.getElementById('tech-skills-container');
    const resumeData = JSON.parse(localStorage.getItem('resumeData'));
    const techSkills = resumeData.techskill || [];

    // 清空容器后重新渲染
    container.innerHTML = '';

    techSkills.forEach((item, index) => {
        const fieldset = document.createElement('fieldset');
        fieldset.innerHTML = `
            <div class="tech"></div>
            <legend>Technical Skill ${index + 1}</legend>
            <label for="skillName${index + 1}">Skill Name:</label>
            <input type="text" id="skillName${index + 1}" name="skillName${index + 1}" value="${item.skill_name || ''}"><br><br>
            <label for="expertise${index + 1}">Expertise:</label>
            <input type="text" id="expertise${index + 1}" name="expertise${index + 1}" value="${item.expertise || ''}"><br><br>
            <label for="yearOfExp${index + 1}">Year of Experience:</label>
            <input type="text" id="yearOfExp${index + 1}" name="yearOfExp${index + 1}" value="${item.year_of_exp || ''}"><br><br>
            <button type="button" onclick="deleteTechSkill(${index})">Delete Technical Skill</button><br><br>
        `;
        container.appendChild(fieldset);

        // 实时监听输入框变化,更新本地存储
        const skillNameInput = fieldset.querySelector(`#skillName${index + 1}`);
        const expertiseInput = fieldset.querySelector(`#expertise${index + 1}`);
        const yearOfExpInput = fieldset.querySelector(`#yearOfExp${index + 1}`);

        skillNameInput.addEventListener('input', () => updateTechSkill(index, 'skill_name', skillNameInput.value));
        expertiseInput.addEventListener('input', () => updateTechSkill(index, 'expertise', expertiseInput.value));
        yearOfExpInput.addEventListener('input', () => updateTechSkill(index, 'year_of_exp', yearOfExpInput.value));
    });
}

// 实时更新单个技术技能数据到本地存储
function updateTechSkill(index, key, value) {
    const resumeData = JSON.parse(localStorage.getItem('resumeData'));
    resumeData.techskill[index][key] = value;
    localStorage.setItem('resumeData', JSON.stringify(resumeData));
}

添加技术技能函数

function addTechSkill() {
    const resumeData = JSON.parse(localStorage.getItem('resumeData'));
    // 添加空技能项
    resumeData.techskill.push({
        skill_name: "",
        expertise: "",
        year_of_exp: ""
    });
    // 更新本地存储并重新渲染
    localStorage.setItem('resumeData', JSON.stringify(resumeData));
    renderTechSkills();
}

删除技术技能函数

function deleteTechSkill(index) {
    const resumeData = JSON.parse(localStorage.getItem('resumeData'));
    // 删除对应索引的技能项
    resumeData.techskill.splice(index, 1);
    // 更新本地存储并重新渲染
    localStorage.setItem('resumeData', JSON.stringify(resumeData));
    renderTechSkills();
}

最终提交至后端函数(用户完成编辑后调用)

function submitResume() {
    const resumeData = localStorage.getItem('resumeData');
    $.ajax({
        url: '/app/submit-resume',
        type: 'POST',
        data: resumeData,
        contentType: 'application/json',
        headers: {
            'X-CSRFToken': '{{ csrf_token }}'
        },
        success: function() {
            alert('简历提交成功');
            // 可选:提交后清空本地存储
            localStorage.removeItem('resumeData');
        },
        error: function() {
            alert('提交失败,请重试');
        }
    });
}

注意事项

  • 数据安全传递:使用Django的json_script过滤器传递初始数据,避免直接嵌入JSON带来的XSS风险
  • 模块复用:教育经历、工作经验等模块可完全复用上述逻辑,仅需修改渲染函数中的数据字段名
  • 本地存储限制:localStorage约有5MB容量限制,简历类数据完全够用,超大数据量需另行处理
  • 状态保留:localStorage数据会在用户关闭页面后保留,若需每次打开重置为初始数据,可删除初始化时的本地存储判断逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 14:32:12