You need to enable JavaScript to run this app. Django:无直接关联下如何在UsuarioSerializer中序列化Producto列表
优惠活动
大模型
产品
解决方案
定价
更多

Django:无直接关联下如何在UsuarioSerializer中序列化Producto列表

问题核心原因

你直接在 UsuarioSerializer 中新增 productos = ProductoSerializer(many=True) 报错,是因为 DRF 序列化器默认会从 Usuario 模型的属性/关联字段中匹配声明的字段数据源,而 Usuario 和 Producto 是跨表间接关联(链路为 Usuario → Orden → Detalle → Producto),没有直接/反向关联字段,序列化器无法自动识别 productos 的数据来源。

解决方案

不需要修改模型,只需通过 DRF 的 SerializerMethodField 自定义返回产品数据,同时优化查询避免 N+1 问题即可,按以下步骤修改:

1. 修改 serializers.py 中的 UsuarioSerializer

from rest_framework import serializers

class UsuarioSerializer(serializers.ModelSerializer):
    cantidad_de_productos = serializers.IntegerField()
    # 新增自定义字段,指定由 get_productos 方法返回数据
    productos = serializers.SerializerMethodField()

    class Meta:
        model = Usuario
        fields = '__all__'

    def get_productos(self, obj):
        # obj 为当前遍历的 Usuario 实例
        # 直接从 Producto 表反向查询当前用户所有订单关联的产品,去重避免重复
        productos = Producto.objects.filter(
            detalles__orden__solicitante=obj
        ).distinct()
        # 用现有 ProductoSerializer 序列化返回
        return ProductoSerializer(productos, many=True).data

如果你需要在产品列表中附带该用户对该产品的总订购数量,可以直接用你已经写好的 ProductosUsuarioSerializer,修改 get_productos 为:

from django.db.models import Sum
def get_productos(self, obj):
    productos = Producto.objects.filter(
        detalles__orden__solicitante=obj
    ).annotate(
        # 聚合该用户对该产品的总订购数量
        cantidad=Sum('detalles__cantidad')
    ).distinct()
    return ProductosUsuarioSerializer(productos, many=True).data

2. 优化 views.py 的查询逻辑,避免 N+1 问题

如果按上面的写法,每个用户都会单独查询一次产品列表,当用户量较大时会出现数据库查询次数过多的问题,可通过 prefetch_related 预加载关联数据:

from django.db.models import Sum, Coalesce
from rest_framework.generics import ListCreateAPIView

class Usuario(ListCreateAPIView):
    queryset = Usuario.objects.annotate(
        cantidad_de_productos=Coalesce(Sum('ordenes__detalles__cantidad'), 0)
    ).prefetch_related(
        # 预加载所有关联的订单、订单项、产品数据,直接复用缓存不额外查库
        'ordenes__detalles__producto'
    )
    serializer_class = UsuarioSerializer

对应修改 get_productos 方法,直接从预加载的缓存中提取数据,无需再查数据库:

def get_productos(self, obj):
    producto_id_set = set()
    productos_list = []
    # 直接从预加载的关联数据中提取,无额外数据库查询
    for orden in obj.ordenes.all():
        for detalle in orden.detalles.all():
            if detalle.producto_id not in producto_id_set:
                producto_id_set.add(detalle.producto_id)
                productos_list.append(detalle.producto)
    return ProductoSerializer(productos_list, many=True).data

修改完成后,返回的 JSON 结构就完全符合要求,不会出现字段找不到的报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 12:36:04