在Django序列化时如何获取外键的外键字段值?
解决Django序列化时获取多层关联字段的问题
问题原因
Django自带的serialize函数启用use_natural_foreign_keys=True时,仅会解析当前模型直接关联的外键的natural key,但不会递归解析关联模型的深层外键(比如Service关联的ServiceCategory),所以无法直接拿到分类名称。
解决方案
方案一:修改模型的natural_key定义(推荐,符合Django原生序列化逻辑)
调整Service的natural_key,让它包含关联分类的信息,同时确保ServiceCategory的name字段唯一(保证natural key的唯一性):
class ServiceCategory(models.Model): name = models.CharField(max_length=50, unique=True) # 增加unique约束 def natural_key(self): return (self.name,) # 用元组返回,符合Django规范 class Service(models.Model): service_category = models.ForeignKey(ServiceCategory, on_delete=models.CASCADE) name = models.CharField(max_length=50) def natural_key(self): # 返回包含自身名称和分类名称的元组 return (self.name, self.service_category.name) # 指定natural_key依赖的模型,帮助Django序列化时预取关联数据 natural_key.dependencies = ['your_app_name.servicecategory'] # 替换为你的实际app名称
保持原序列化代码不变:
data = Request.objects.all() data = serialize("json", data, use_natural_foreign_keys=True)
此时序列化后的JSON中,每个Service条目会以数组形式包含自身名称和分类名称。
方案二:手动构造序列化数据(无需修改模型)
通过预取关联数据避免N+1查询,然后手动遍历构造需要的数据结构再转成JSON:
from django.db.models import Prefetch import json # 预取多层关联数据,提升查询效率 requests = Request.objects.prefetch_related( Prefetch('services', queryset=Service.objects.select_related('service_category')) ).all() # 构造自定义数据结构 result = [] for req in requests: service_list = [] for service in req.services.all(): service_list.append({ "name": service.name, "service_category": service.service_category.name }) result.append({ "name": req.name, "services": service_list }) # 转为JSON格式 data = json.dumps(result)
方案三:使用Django REST Framework序列化器(适合已使用DRF的项目)
如果项目中已经集成DRF,这种方式更灵活,可轻松处理多层关联:
首先定义序列化器:
from rest_framework import serializers from .models import Request, Service, ServiceCategory class ServiceCategorySerializer(serializers.ModelSerializer): class Meta: model = ServiceCategory fields = ['name'] class ServiceSerializer(serializers.ModelSerializer): service_category = ServiceCategorySerializer() class Meta: model = Service fields = ['name', 'service_category'] class RequestSerializer(serializers.ModelSerializer): services = ServiceSerializer(many=True) class Meta: model = Request fields = ['name', 'services']
然后执行序列化:
from rest_framework.renderers import JSONRenderer requests = Request.objects.prefetch_related('services__service_category').all() serializer = RequestSerializer(requests, many=True) data = JSONRenderer().render(serializer.data)
内容的提问来源于stack exchange,提问作者aboveandbeyond
相关产品推荐
相关产品推荐

