如何在序列化深度2的关联模型时跳过深度1的中间模型?
Django REST Framework 跨关联模型直接序列化用户信息问题
问题场景
有三个外键关联的模型,关联关系为 Order -> Customer -> User,需要在订单的ViewSet序列化输出时,直接展示对应的User信息,不包含中间的Customer层级。
模型定义
from django.db import models class Order(models.Model): customer = models.ForeignKey("customers.Customer", on_delete=models.CASCADE) class Customer(models.Model): user = models.ForeignKey("users.User", on_delete=models.CASCADE) class User(models.Model): name = models.CharField(max_length=64)
尝试的序列化器与视图
序列化器代码
from rest_framework import serializers from .models import Order, User class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ["name"] class OrderSerializer(serializers.ModelSerializer): user = UserSerializer(source="customer__user", read_only=True) class Meta: model = Order fields = ["id", "user"]
视图集代码
from rest_framework import viewsets from .models import Order from .serializers import OrderSerializer class OrderViewSet(viewsets.ModelViewSet): queryset = Order.objects.all() serializer_class = OrderSerializer
问题现象
- 期望输出:
[ {"id": 1, "user": {"name": "John"}}, {"id": 2, "user": {"name": "Mary"}} ]
- 实际输出:
[ {"id": 1}, {"id": 2} ]
若通过中间的Customer序列化器中转,虽然能正常输出,但会包含多余的Customer层级:
中转序列化器代码
class CustomerSerializer(serializers.ModelSerializer): user = UserSerializer(read_only=True) class Meta: model = Customer fields = ["user"] class OrderSerializer(serializers.ModelSerializer): customer = CustomerSerializer(read_only=True) class Meta: model = Order fields = ["id", "customer"]
中转方式输出结果
[ {"id": 1, "customer": {"user": {"name": "John"}}}, {"id": 2, "customer": {"user": {"name": "Mary"}}} ]
解决方案
方法1:使用SerializerMethodField手动序列化用户信息
修改OrderSerializer,通过自定义方法获取并序列化User对象:
class OrderSerializer(serializers.ModelSerializer): user = serializers.SerializerMethodField() def get_user(self, obj): return UserSerializer(obj.customer.user).data class Meta: model = Order fields = ["id", "user"]
同时为避免N+1查询性能问题,在视图集的queryset中预取关联数据:
class OrderViewSet(viewsets.ModelViewSet): queryset = Order.objects.select_related('customer__user') serializer_class = OrderSerializer
方法2:使用属性链式访问替代双下划线写法
直接使用属性链式访问作为source,替代ORM查询的双下划线语法:
class OrderSerializer(serializers.ModelSerializer): user = UserSerializer(source="customer.user", read_only=True) class Meta: model = Order fields = ["id", "user"]
同样需要在queryset中添加select_related('customer__user')优化查询性能。
问题原因说明
原代码中source="customer__user"的双下划线是ORM查询语法,但嵌套序列化器的source参数不支持自动解析该语法来获取关联对象,导致无法正确读取User实例,因此对应字段无输出。使用属性链式访问customer.user或SerializerMethodField可以直接获取到关联的User实例,完成序列化。
内容的提问来源于stack exchange,提问作者Leevi L
相关产品推荐
相关产品推荐

