如何在Vue.js与Django中关联合并Party与Leads表数据
问题描述
我正在开发一款应用,Party表存储客户基础信息,Leads表存储同一客户的更多信息。两者通过Party_ID关联(Party表的主键,Leads表的外键),但无法在Vue.js前端的ag-grid表格中合并展示这两张表的数据。以下是相关代码:
Party表前端组件
<template> <div class="tasks_container"> <div class="tasks_content"> <h1>Party table</h1> <ag-grid-vue style="width:1310px; height: 650px" class="ag-theme-alpine" :columnDefs="columnDefs" :rowData="rowData" > </ag-grid-vue> </div> </div> </template> <script> import axios from 'axios'; import "ag-grid-community/styles/ag-grid.css"; import "ag-grid-community/styles/ag-theme-alpine.css"; import { AgGridVue } from "ag-grid-vue3"; import 'ag-grid-enterprise'; export default { components: { AgGridVue, }, data() { return { columnDefs: null, rowData: null, } }, mounted(){ this.columnDefs=[ {field:'FIRST_NAME',headerName: 'First name'}, {field:'LAST_NAME',headerName: 'Last name'}, {field:'PARTY_TYPE',headerName: 'Party Type'}, {field:'PRIMARY_NO',headerName: 'Main number'}, {field:'WHATSAPP_NO',headerName: 'Whatsapp number'}, {field:'EMAIL_ID',headerName: 'Email ID'}, {field:'PREFERRED_CONTACT_METHOD',headerName: 'Preferred contact'}, ]; axios.get('http://127.0.0.1:8000/request1') .then(response=>this.rowData=response.data) }, } </script> <style scoped> .ag-theme-alpine { --ag-foreground-color: rgb(2, 1, 2); --ag-background-color: rgb(245, 244, 243); --ag-header-foreground-color: rgb(204, 245, 172); --ag-header-background-color: rgb(64, 103, 209); --ag-odd-row-background-color: rgb(0, 0, 0, 0.03); --ag-header-column-resize-handle-color: rgb(236, 230, 236); --ag-font-size: 17px; --ag-font-family: monospace; } </style>
Leads表前端组件
<template> <div class="tasks_container"> <div class="tasks_content"> <h1>Lead table</h1> <ag-grid-vue style="width: 1330px; height: 850px" class="ag-theme-alpine" :columnDefs="columnDefs" :rowData="rowData" > </ag-grid-vue> </div> </div> </template> <script> import axios from 'axios'; import "ag-grid-community/styles/ag-grid.css"; import "ag-grid-community/styles/ag-theme-alpine.css"; import { AgGridVue } from "ag-grid-vue3"; import 'ag-grid-enterprise'; export default { components: { AgGridVue, }, data() { return { columnDefs: null, rowData: null, } }, mounted(){ this.columnDefs=[ {field:'LEAD_NAME'}, {field:'DESCRIPTION'}, {field:'LEAD_STATUS'}, {field:'LEAD_SOURCE'}, {field:'PARTY_ID'}, ]; axios.get('http://127.0.0.1:8000/request2') .then(response=>this.rowData=response.data) }, } </script>
后端代码
views.py
from django.shortcuts import render from django.views.decorators.csrf import csrf_exempt from rest_framework.parsers import JSONParser from django.http.response import JsonResponse from CRM.models import party,leads,lookup_names,lookup_names_values from CRM.serializers import partySerializer,leadsSerializer,lookup_namesSerializer,lookup_names_valuesSerializer @csrf_exempt def partyAPI(request,id=0): if request.method=='GET': partys=party.objects.all() party_serializers= partySerializer(partys,many=True) return JsonResponse(party_serializers.data,safe=False) elif request.method=='POST': partys_data=JSONParser().parse(request) party_serializers=partySerializer(data=partys_data) if party_serializers.is_valid(): party_serializers.save() return JsonResponse("20",safe=False) elif request.method=='PUT': partys_data=JSONParser().parse(request) partys=party.objects.get(Party_ID=partys_data['Party_ID']) party_serializers=partySerializer(partys,data=partys_data) if party_serializers.is_valid(): party_serializers.save() return JsonResponse("19",safe=False) return JsonResponse("Failed") elif request.method=='DELETE': partys=party.objects.get(Party_ID=id) partys.delete() return JsonResponse("Deleted",safe=False) @csrf_exempt def leadsAPI(request,id=0): if request.method=='GET': leadss=leads.objects.all() leads_serializers= leadsSerializer(leadss,many=True) return JsonResponse(leads_serializers.data,safe=False) elif request.method=='POST': leads_data=JSONParser().parse(request) leads_serializers=leadsSerializer(data=leads_data) if leads_serializers.is_valid(): leads_serializers.save() return JsonResponse("20",safe=False) elif request.method=='PUT': leads_data=JSONParser().parse(request) leadss=leads.objects.get(LEAD_ID=leads_data['LEAD_ID']) leads_serializers=leadsSerializer(leadss,data=leads_data) if leads_serializers.is_valid(): leads_serializers.save() return JsonResponse("Added",safe=False) return JsonResponse("Failed") elif request.method =='DELETE': leadss=leads.objects.get(LEAD_ID=id) leadss.delete() return JsonResponse("deleted",safe=False)
Models.py
from django.db import models import datetime class party(models.Model): Party_ID = models.AutoField(primary_key=True) FIRST_NAME = models.CharField(max_length=100) LAST_NAME = models.CharField(max_length=100) PARTY_TYPE = models.CharField(max_length=2000) PRIMARY_NO = models.IntegerField() WHATSAPP_NO = models.IntegerField() EMAIL_ID = models.CharField(max_length=100) PREFERRED_CONTACT_METHOD = models.CharField(max_length=100) CREATED_BY = models.IntegerField(default=-1) CREATION_DATE = models.DateField(default=datetime.date.today) LAST_UPDATE_DATE = models.DateField(default=datetime.date.today) TENANT_MAP_ID = models.IntegerField(default=1) class leads(models.Model): LEAD_ID = models.AutoField(primary_key=True) LEAD_NAME = models.CharField(max_length=100) DESCRIPTION = models.CharField(max_length=2000) LEAD_STATUS = models.CharField(max_length=100) LEAD_SOURCE = models.CharField(max_length=500) CREATED_BY = models.IntegerField(default=-1) CREATION_DATE = models.DateField(default=datetime.date.today) LAST_UPDATE_DATE = models.DateField(default=datetime.date.today) PARTY_ID = models.ForeignKey(party, on_delete=models.CASCADE) TENANT_MAP_ID = models.IntegerField(default=1)
希望找到合并两张表数据展示的方法,要求功能正常、界面美观。
解决方案
有两种可行方案,推荐优先使用后端联表查询,减少前端数据处理逻辑,同时保证数据一致性。
方案一:后端联表查询返回合并数据
步骤1:修改Serializer,关联Leads数据
在partySerializer中嵌套leadsSerializer,自动带出关联的Leads信息:
# CRM/serializers.py from rest_framework import serializers from .models import party, leads class leadsSerializer(serializers.ModelSerializer): class Meta: model = leads fields = ('LEAD_NAME', 'DESCRIPTION', 'LEAD_STATUS', 'LEAD_SOURCE') class partySerializer(serializers.ModelSerializer): leads_set = leadsSerializer(many=True, read_only=True) # Django自动生成反向关联名 class Meta: model = party fields = ('Party_ID', 'FIRST_NAME', 'LAST_NAME', 'PARTY_TYPE', 'PRIMARY_NO', 'WHATSAPP_NO', 'EMAIL_ID', 'PREFERRED_CONTACT_METHOD', 'leads_set')
步骤2:前端修改为单组件展示合并数据
创建合并后的表格组件,将关联的Leads数据转为平级行展示:
<template> <div class="tasks_container"> <div class="tasks_content"> <h1>客户与线索合并表</h1> <ag-grid-vue style="width: 1600px; height: 700px" class="ag-theme-alpine" :columnDefs="columnDefs" :rowData="rowData" > </ag-grid-vue> </div> </div> </template> <script> import axios from 'axios'; import "ag-grid-community/styles/ag-grid.css"; import "ag-grid-community/styles/ag-theme-alpine.css"; import { AgGridVue } from "ag-grid-vue3"; import 'ag-grid-enterprise'; export default { components: { AgGridVue, }, data() { return { columnDefs: [ {field:'FIRST_NAME',headerName: '姓名'}, {field:'LAST_NAME',headerName: '姓氏'}, {field:'PARTY_TYPE',headerName: '客户类型'}, {field:'PRIMARY_NO',headerName: '主号码'}, {field:'WHATSAPP_NO',headerName: 'WhatsApp号码'}, {field:'EMAIL_ID',headerName: '邮箱'}, {field:'PREFERRED_CONTACT_METHOD',headerName: '首选联系方式'}, {field:'LEAD_NAME',headerName: '线索名称'}, {field:'DESCRIPTION',headerName: '线索描述'}, {field:'LEAD_STATUS',headerName: '线索状态'}, {field:'LEAD_SOURCE',headerName: '线索来源'} ], rowData: null } }, async mounted(){ const response = await axios.get('http://127.0.0.1:8000/request1'); // 处理一对多关联:每个线索生成一行客户数据 const mergedData = []; response.data.forEach(party => { if (party.leads_set?.length) { party.leads_set.forEach(lead => { mergedData.push({ ...party, ...lead, leads_set: undefined }); }); } else { mergedData.push({ ...party, LEAD_NAME: '-', DESCRIPTION: '-', LEAD_STATUS: '-', LEAD_SOURCE: '-', leads_set: undefined }); } }); this.rowData = mergedData; }, } </script> <style scoped> .ag-theme-alpine { --ag-foreground-color: rgb(2, 1, 2); --ag-background-color: rgb(245, 244, 243); --ag-header-foreground-color: rgb(204, 245, 172); --ag-header-background-color: rgb(64, 103, 209); --ag-odd-row-background-color: rgb(0, 0, 0, 0.03); --ag-header-column-resize-handle-color: rgb(236, 230, 236); --ag-font-size: 17px; --ag-font-family: monospace; } </style>
方案二:前端获取两个数据集后合并
如果不想修改后端,可在前端并行获取两个数据集后,通过Party_ID关联合并:
<template> <!-- 同方案一模板 --> </template> <script> export default { // ... async mounted(){ // 并行拉取两个接口数据 const [partyRes, leadsRes] = await Promise.all([ axios.get('http://127.0.0.1:8000/request1'), axios.get('http://127.0.0.1:8000/request2') ]); const partyData = partyRes.data; const leadsData = leadsRes.data; // 合并数据 const mergedData = partyData.flatMap(party => { const relatedLeads = leadsData.filter(lead => lead.PARTY_ID === party.Party_ID); return relatedLeads.length ? relatedLeads.map(lead => ({...party, ...lead})) : [{...party, LEAD_NAME: '-', DESCRIPTION: '-', LEAD_STATUS: '-', LEAD_SOURCE: '-'}]; }); this.rowData = mergedData; this.columnDefs = [ {field:'FIRST_NAME',headerName: '姓名'}, {field:'LAST_NAME',headerName: '姓氏'}, {field:'PARTY_TYPE',headerName: '客户类型'}, {field:'PRIMARY_NO',headerName: '主号码'}, {field:'WHATSAPP_NO',headerName: 'WhatsApp号码'}, {field:'EMAIL_ID',headerName: '邮箱'}, {field:'PREFERRED_CONTACT_METHOD',headerName: '首选联系方式'}, {field:'LEAD_NAME',headerName: '线索名称'}, {field:'DESCRIPTION',headerName: '线索描述'}, {field:'LEAD_STATUS',headerName: '线索状态'}, {field:'LEAD_SOURCE',headerName: '线索来源'} ]; } } </script>
内容的提问来源于stack exchange,提问作者Anshul Raj
相关产品推荐
相关产品推荐

