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
相关产品推荐
相关产品推荐

