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

Django:如何遍历两个一对多数据表关联关系?

实现单公司展示关联职位与项目的网页方案

嘿,我懂你要做的事儿——一个能按公司维度展示关联职位和项目的网页,每个公司只出现一次,还能切换查看不同公司的内容对吧?结合你提到的Company和Position、Project的一对多关联,我给你整理了一套落地的思路和代码示例,应该能解决你现在的问题:

第一步:先把数据理顺

不管是后端返回还是前端模拟数据,核心是要把重复的公司数据聚合起来,确保每个公司对象里直接包含对应的职位和项目数组,避免渲染时重复显示公司。

理想的数据结构(后端返回或前端处理后)

// 模拟聚合好的公司数据
const companiesData = [
  {
    id: 1,
    name: "Alpha科技",
    description: "专注AI领域的科技公司",
    positions: [
      { id: 101, title: "前端开发工程师", department: "技术部" },
      { id: 102, title: "产品经理", department: "产品部" }
    ],
    projects: [
      { id: 201, name: "智能客服系统", status: "已完成" },
      { id: 202, name: "AI图像识别平台", status: "进行中" }
    ]
  },
  {
    id: 2,
    name: "Beta制造",
    description: "高端制造业企业",
    positions: [
      { id: 103, title: "机械工程师", department: "研发部" },
      { id: 104, title: "质量检测员", department: "质检部" }
    ],
    projects: [
      { id: 203, name: "自动化生产线升级", status: "已完成" },
      { id: 204, name: "新能源零件研发", status: "已完成" }
    ]
  }
];

如果后端返回平铺数据,前端可以这样聚合

要是后端给你的是公司+职位/项目的平铺记录,你可以用这个函数把数据整理成上面的结构:

// 处理平铺数据为聚合结构的工具函数
function aggregateCompanies(rawData) {
  const companyMap = {};
  rawData.forEach(item => {
    // 先初始化公司信息(避免重复)
    if (!companyMap[item.companyId]) {
      companyMap[item.companyId] = {
        id: item.companyId,
        name: item.companyName,
        description: item.companyDesc,
        positions: [],
        projects: []
      };
    }
    // 添加关联职位(去重)
    if (item.positionId && !companyMap[item.companyId].positions.some(p => p.id === item.positionId)) {
      companyMap[item.companyId].positions.push({
        id: item.positionId,
        title: item.positionTitle,
        department: item.department
      });
    }
    // 添加已完成项目(按需求过滤+去重)
    if (item.projectId && item.projectStatus === "已完成" && !companyMap[item.companyId].projects.some(p => p.id === item.projectId)) {
      companyMap[item.companyId].projects.push({
        id: item.projectId,
        name: item.projectName,
        status: item.projectStatus
      });
    }
  });
  return Object.values(companyMap);
}

第二步:前端页面实现(带切换功能)

下面是完整的HTML+JS代码,实现公司信息展示、关联职位/项目渲染,以及前后切换公司的功能:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>公司信息展示</title>
  <style>
    .company-card {
      border: 1px solid #eee;
      padding: 20px;
      margin: 20px auto;
      width: 80%;
      border-radius: 8px;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }
    .section-title {
      color: #2c3e50;
      margin-top: 20px;
      margin-bottom: 10px;
      border-bottom: 1px solid #eee;
      padding-bottom: 5px;
    }
    .nav-buttons {
      text-align: center;
      margin: 20px 0;
    }
    .nav-btn {
      padding: 8px 18px;
      margin: 0 5px;
      cursor: pointer;
      border: none;
      border-radius: 4px;
      background-color: #3498db;
      color: white;
    }
    .nav-btn:disabled {
      background-color: #bdc3c7;
      cursor: not-allowed;
    }
    ul {
      list-style-type: square;
      padding-left: 20px;
    }
  </style>
</head>
<body>
  <div class="nav-buttons">
    <button class="nav-btn" id="prevBtn">上一家公司</button>
    <button class="nav-btn" id="nextBtn">下一家公司</button>
  </div>

  <div class="company-card" id="companyContainer">
    <!-- 动态渲染的公司信息会放在这里 -->
  </div>

  <script>
    // 假设已经有了聚合后的companiesData
    const companiesData = [
      {
        id: 1,
        name: "Alpha科技",
        description: "专注AI领域的科技公司",
        positions: [
          { id: 101, title: "前端开发工程师", department: "技术部" },
          { id: 102, title: "产品经理", department: "产品部" }
        ],
        projects: [
          { id: 201, name: "智能客服系统", status: "已完成" },
          { id: 202, name: "AI图像识别平台", status: "进行中" }
        ]
      },
      {
        id: 2,
        name: "Beta制造",
        description: "高端制造业企业",
        positions: [
          { id: 103, title: "机械工程师", department: "研发部" },
          { id: 104, title: "质量检测员", department: "质检部" }
        ],
        projects: [
          { id: 203, name: "自动化生产线升级", status: "已完成" },
          { id: 204, name: "新能源零件研发", status: "已完成" }
        ]
      }
    ];
    let currentIndex = 0;

    // 渲染当前公司信息的函数
    function renderCurrentCompany() {
      const company = companiesData[currentIndex];
      const container = document.getElementById('companyContainer');
      container.innerHTML = `
        <h2>${company.name}</h2>
        <p>${company.description}</p>
        
        <h3 class="section-title">关联职位</h3>
        <ul>
          ${company.positions.map(pos => `<li>${pos.title} - ${pos.department}</li>`).join('')}
        </ul>
        
        <h3 class="section-title">已完成项目</h3>
        <ul>
          ${company.projects.map(proj => `<li>${proj.name}</li>`).join('')}
        </ul>
      `;
      // 处理切换按钮的禁用状态(边界判断)
      document.getElementById('prevBtn').disabled = currentIndex === 0;
      document.getElementById('nextBtn').disabled = currentIndex === companiesData.length - 1;
    }

    // 绑定切换按钮的事件
    document.getElementById('prevBtn').addEventListener('click', () => {
      if (currentIndex > 0) {
        currentIndex--;
        renderCurrentCompany();
      }
    });

    document.getElementById('nextBtn').addEventListener('click', () => {
      if (currentIndex < companiesData.length - 1) {
        currentIndex++;
        renderCurrentCompany();
      }
    });

    // 页面加载时渲染第一个公司
    renderCurrentCompany();
  </script>
</body>
</html>

几个关键注意点

  • 数据聚合是核心:不管后端还是前端处理,一定要确保每个公司只存在一条记录,关联的职位和项目都放在对应数组里,这是避免公司重复显示的关键。
  • 切换边界处理:记得在切换到第一家或最后一家公司时禁用对应按钮,防止用户无效操作。
  • 项目筛选:如果需求是只展示已完成项目,上面的代码已经在聚合和渲染时做了过滤,你可以根据实际需求调整过滤条件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:44:30