You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DRF如何用Serializer生成嵌套JSON?遇属性错误求助

解决方案

1. 修正模型关联(核心问题)

你的两个模型之间没有建立关联,导致ShopIndexPage实例不存在对应关联字段的属性。给SwiperImage添加外键关联到ShopIndexPage,并指定反向关联名称:

# models.py
from django.db import models

class ShopIndexPage(models.Model):
    shop_name = models.CharField(max_length=128, default="Shop Name")
    intro_text = models.CharField(max_length=1000, default="Intro Text")

    def __str__(self):
        return "Shop text of " + self.shop_name

class SwiperImage(models.Model):
    # 添加外键,related_name指定反向关联名称,匹配目标JSON的swiper_images键
    shop = models.ForeignKey(ShopIndexPage, on_delete=models.CASCADE, related_name='swiper_images')
    swiper_image = models.ImageField(upload_to='images/index/swiper-images', default="None")
    swiper_image_alt = models.CharField(max_length=100, null=True, blank=True)

    def __str__(self):
        return self.swiper_image_alt or "Swiper Image"

2. 调整序列化器,匹配目标JSON结构

修改序列化器,使用正确的关联字段名,映射模型字段到目标JSON的键名:

# serializers.py
from rest_framework import serializers
from .models import ShopIndexPage, SwiperImage

class SwiperImageSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(read_only=True)  # 显式包含目标JSON需要的id字段
    # 若需要返回完整图片URL,替换为SerializerMethodField(可选)
    swiper_image = serializers.SerializerMethodField()

    def get_swiper_image(self, obj):
        request = self.context.get('request')
        if obj.swiper_image:
            return request.build_absolute_uri(obj.swiper_image.url)
        return None

    class Meta:
        model = SwiperImage
        fields = ['id', 'swiper_image', 'swiper_image_alt']

class ShopIndexPageSerializer(serializers.ModelSerializer):
    # 使用模型反向关联的名称swiper_images,对应目标JSON的键
    swiper_images = SwiperImageSerializer(many=True)
    # 将模型的intro_text映射为目标JSON的shop_intro
    shop_intro = serializers.CharField(source='intro_text')

    class Meta:
        model = ShopIndexPage
        fields = ['shop_name', 'shop_intro', 'swiper_images']

    # 重写create方法,支持POST创建嵌套数据
    def create(self, validated_data):
        swiper_images_data = validated_data.pop('swiper_images')
        shop_page = ShopIndexPage.objects.create(**validated_data)
        for img_data in swiper_images_data:
            SwiperImage.objects.create(shop=shop_page, **img_data)
        return shop_page

3. 优化视图,传递request上下文并提升查询性能

修改视图,传入request上下文用于生成完整图片URL,同时用prefetch_related避免N+1查询:

# views.py
from .models import ShopIndexPage
from .serializers import ShopIndexPageSerializer
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status

@api_view(['GET', 'POST'])
def index_list(request, format=None):
    if request.method == "GET":
        # 预加载关联的轮播图,提升查询性能
        index_queryset = ShopIndexPage.objects.prefetch_related('swiper_images').all()
        # 传入request上下文,用于生成图片完整URL
        serializer = ShopIndexPageSerializer(index_queryset, many=True, context={'request': request})
        return Response(serializer.data)

    elif request.method == "POST":
        serializer = ShopIndexPageSerializer(data=request.data, context={'request': request})
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

4. 配置媒体文件访问(可选,若需图片URL正常访问)

在项目settings.py中添加媒体文件配置:

MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

在项目根urls.py中添加媒体文件路由:

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    # 你的其他路由
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

错误原因说明

之前的错误是因为ShopIndexPage和SwiperImage没有建立数据库关联,DRF序列化器无法在ShopIndexPage实例上找到swiper_items属性。通过添加外键和指定related_name,两个模型建立了一对多关联,ShopIndexPage实例会自动拥有swiper_images属性(即该店铺下的所有轮播图),序列化器就能正确读取并嵌套输出数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 09:15:01