如何通过Axios将Django外键模型实例传递至React
问题:从User实例中关联获取完整地址层级数据
我有一个Address模型,通过外键关联多个地址细分模型;还有一个User模型,通过外键关联单个Address实例。现在需要从User对象中获取完整的地址层级数据(比如User->Address->type->type_code、User->Address->province->province_name这类嵌套结构),并将包含地址信息的用户数据传给React前端存储使用。
一、Models.py 代码
class AddressType(models.Model): add_type_name = models.CharField(_("Address Type"), max_length=30) add_type_code = models.CharField(_("Address Type Code "), max_length=2) def __str__(self): return self.add_type_name class AddressProvince(models.Model): add_prov_name = models.CharField(_("Province Name"), max_length=20) def __str__(self): return self.add_prov_name class AddressBranch(models.Model): add_branch_name = models.CharField(_("Branch Name"), max_length=100) add_branch_code = models.CharField(_("Branch Code"), max_length=10) def __str__(self): return self.add_branch_name class AddressDepartment(models.Model): add_dept_name = models.CharField(_("Department Name"), max_length=150) add_dept_code = models.CharField(_("Department Code "), max_length=5) add_dept_floor = models.PositiveIntegerField(_("Department Floor"), default=0) def __str__(self): return self.add_dept_name class AddressContact(models.Model): add_cont_name = models.CharField(_("Contact Name"), max_length=200) add_cont_position = models.CharField(_("Contact Position"), max_length=200) def __str__(self): return self.add_cont_name class AddressSection(models.Model): add_sec_name = models.CharField(_("Section Name"), max_length=250) class Meta: verbose_name_plural = "Address Section" def __str__(self): return self.add_sec_name class Address(models.Model): add_type = models.ForeignKey(AddressType, on_delete=models.CASCADE, blank=True, null=True, related_name="address_type") add_prov = models.ForeignKey(AddressProvince, on_delete=models.CASCADE, blank=True, null=True,related_name="address_province") add_branch = models.ForeignKey(AddressBranch, on_delete=models.CASCADE, blank=True, null=True,related_name="address_branch") add_dept = models.ForeignKey(AddressDepartment, on_delete=models.CASCADE,blank=True, null=True, related_name="address_department") add_contact = models.ForeignKey(AddressContact, on_delete=models.CASCADE,blank=True, null=True, related_name="address_contact") add_section = models.ForeignKey(AddressSection, on_delete=models.CASCADE,blank=True, null=True, related_name="address_section") add_is_sys = models.BooleanField(_("Is System User?"), default=False) def __str__(self): return self.add_section.add_sec_name class UserGroup(models.Model): user_group_name = models.CharField(_("Group"), max_length=100) user_group_code = models.CharField(_("Group Code"), max_length=2) def __str__(self): return self.user_group_code class User(models.Model): user_name = models.CharField(_("Name"), max_length=180) user_password = models.CharField(_("Password"), max_length=100) user_email = models.CharField(_("Email"), max_length=150) user_AZB = models.CharField(_("AZB"), max_length=20) user_group = models.ForeignKey(UserGroup, on_delete=models.CASCADE, related_name="user_group") user_position = models.CharField(_("Position"), max_length=100) user_address = models.ForeignKey(Address, on_delete=models.CASCADE, related_name="user_address")
二、Views.py 中的登录接口代码
@csrf_exempt def userLogin(request): email = request.POST.get('user_email') password = request.POST.get('user_password') user = models.User.objects.get(user_email = email , user_password = password) userData = ser.serialize('json', [user]) userAddress = fetch_address(user.user_address.id) if user: return JsonResponse( userData, userAddress, safe=False) else: return JsonResponse({'bool': False})
三、React Login.jsx 提交代码
const submitForm = (e)=>{ e.preventDefault() const userFormData = new FormData; userFormData.append('user_email', userData.user_email) userFormData.append('user_password', userData.user_password) axios.post(baseURL+'/login/', userFormData). then((res)=>{ // sessionStorage.setItem('userLoggedIn', true) // sessionStorage.setItem('userData', JSON.stringify(res.data.user[0])) }).catch((err)=>{ console.log(err.response.data) }) }
四、尝试编写的地址获取函数(报错)
编写了fetch_address函数尝试获取完整地址信息,但运行时报错:TypeError: 'str' object is not callable
def fetch_address(add_id): findAddress = models.Address.objects.get(pk=add_id) data = [] if findAddress: data.append({"add_id": add_id}) if findAddress.add_type: addType = models.AddressType.objects.get(pk=findAddress.add_type.id) data.append ({ "add_type_name" : addType.add_type_name, "add_type_code" : addType.add_type_code, "add_type_id" : findAddress.add_type.id, }) if findAddress.add_prov: addProv = models.AddressProvince.objects.get(pk=findAddress.add_prov.id) data.append({ "add_prov_name" : addProv.add_prov_name, "add_prov_id" : findAddress.add_prov.id, }) if findAddress.add_branch: addBranch = models.AddressBranch.objects.get(pk=findAddress.add_branch.id) data.append({ "add_branch_code" : addBranch.add_branch_code, "add_branch_name" : addBranch.add_branch_name, "add_branch_id" : findAddress.add_prov.id, }) if findAddress.add_dept: addDept = models.AddressDepartment.objects.get(pk=findAddress.add_dept.id) data.append({ "add_dept_code": addDept.add_dept_code, "add_dept_name": addDept.add_dept_name, "add_dept_floor": addDept.add_dept_floor, "add_dept_id": findAddress.add_dept.id }) if findAddress.add_contact: addContact = models.AddressContact.objects.get(pk=findAddress.add_contact.id) data.append({ "add_cont_code": addContact.add_cont_name, "add_cont_pos": addContact.add_cont_position, "add_cont_id": findAddress.add_contact.id }) if findAddress.add_section: addSection = models.AddressSection.objects.get(pk=findAddress.add_section.id) data.append({ "add_sec_name": addSection.add_sec_name, "add_sec_id": findAddress.add_contact.id }) if data: return json.dumps(data) else: return {}
问题修正方案
1. 修复fetch_address函数的错误
原函数存在返回值类型混乱、字段引用错误、重复查询关联对象等问题,修正后:
def fetch_address(add_id): find_address = models.Address.objects.get(pk=add_id) address_data = { "add_id": add_id, "add_type": {}, "add_prov": {}, "add_branch": {}, "add_dept": {}, "add_contact": {}, "add_section": {} } if find_address.add_type: address_data["add_type"] = { "add_type_name": find_address.add_type.add_type_name, "add_type_code": find_address.add_type.add_type_code, "add_type_id": find_address.add_type.id } if find_address.add_prov: address_data["add_prov"] = { "add_prov_name": find_address.add_prov.add_prov_name, "add_prov_id": find_address.add_prov.id } if find_address.add_branch: address_data["add_branch"] = { "add_branch_code": find_address.add_branch.add_branch_code, "add_branch_name": find_address.add_branch.add_branch_name, "add_branch_id": find_address.add_branch.id } if find_address.add_dept: address_data["add_dept"] = { "add_dept_code": find_address.add_dept.add_dept_code, "add_dept_name": find_address.add_dept.add_dept_name, "add_dept_floor": find_address.add_dept.add_dept_floor, "add_dept_id": find_address.add_dept.id } if find_address.add_contact: address_data["add_contact"] = { "add_cont_name": find_address.add_contact.add_cont_name, "add_cont_position": find_address.add_contact.add_cont_position, "add_cont_id": find_address.add_contact.id } if find_address.add_section: address_data["add_section"] = { "add_sec_name": find_address.add_section.add_sec_name, "add_sec_id": find_address.add_section.id } # 移除空字段,只保留有数据的内容 return {k: v for k, v in address_data.items() if v}
2. 修复Views.py中的登录接口
原接口JsonResponse传参错误,且未正确合并用户与地址数据,修正后:
import json from django.core import serializers @csrf_exempt def userLogin(request): email = request.POST.get('user_email') password = request.POST.get('user_password') try: # 预加载所有关联模型,避免N+1查询 user = models.User.objects.select_related( 'user_address', 'user_address__add_type', 'user_address__add_prov', 'user_address__add_branch', 'user_address__add_dept', 'user_address__add_contact', 'user_address__add_section' ).get(user_email=email, user_password=password) # 序列化用户数据并转为字典 user_data = json.loads(serializers.serialize('json', [user]))[0]['fields'] user_data['id'] = user.id # 合并地址数据 user_data['user_address'] = fetch_address(user.user_address.id) return JsonResponse(user_data, safe=False) except models.User.DoesNotExist: return JsonResponse({'bool': False})
3. 前端React代码调整
现在后端返回包含完整地址层级的用户对象,前端可直接存储并访问:
const submitForm = (e)=>{ e.preventDefault() const userFormData = new FormData; userFormData.append('user_email', userData.user_email) userFormData.append('user_password', userData.user_password) axios.post(baseURL+'/login/', userFormData) .then((res)=>{ sessionStorage.setItem('userLoggedIn', true) sessionStorage.setItem('userData', JSON.stringify(res.data)) // 示例:访问地址层级数据 const storedUser = JSON.parse(sessionStorage.getItem('userData')) console.log(storedUser.user_address.add_type.add_type_code) console.log(storedUser.user_address.add_prov.add_prov_name) }).catch((err)=>{ console.log(err.response.data) }) }
内容的提问来源于stack exchange,提问作者Mr.Trent
相关产品推荐
相关产品推荐

