Django 2.0+DRF3.8.0下GET接口JSON嵌套格式改造求助
搞定DRF返回嵌套JSON数组的问题
嘿,我来帮你解决这个DRF序列化的问题!你现在用的是Django 2.0 + DRF 3.8.0,想要让GET接口返回嵌套的JSON数组结构,但目前只能拿到平级的列表,对吧?
首先得明确下你期望的目标嵌套格式大概是什么样的?比如是不是类似这样:
{ "student": { "id": 1, "name": "张三" }, "lectures": [ { "id": 1, "title": "数学导论" }, { "id": 2, "title": "计算机基础" } ] }
而不是现在返回的[ {"id":1, ...}, {"id":2, ...} ]这种普通数组?
我先基于常见的模型结构给你解决方案,要是你的实际代码和我假设的不一样,随时调整就行:
1. 先假设你的模型结构(如果不符,替换成你的实际代码)
一般这种场景的模型大概是这样:
from django.db import models class Student(models.Model): name = models.CharField(max_length=100) # 其他字段比如学号、年级之类的... class Lecture(models.Model): title = models.CharField(max_length=200) teacher = models.CharField(max_length=100) # 其他字段比如上课时间... class StudentLecture(models.Model): student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='enrolled_lectures') lecture = models.ForeignKey(Lecture, on_delete=models.CASCADE) enroll_date = models.DateTimeField(auto_now_add=True)
2. 调整序列化器,实现嵌套结构
要生成嵌套JSON,得用嵌套序列化器或者SerializerMethodField来关联关联数据。这里分两种常见情况:
情况一:返回某个学生的所有选课信息(学生为主体,嵌套课程列表)
from rest_framework import serializers from .models import Student, Lecture, StudentLecture # 先定义课程的基础序列化器 class LectureSerializer(serializers.ModelSerializer): class Meta: model = Lecture fields = ('id', 'title', 'teacher') # 选你需要返回的字段 # 定义学生的嵌套序列化器,包含其选课列表 class StudentWithLecturesSerializer(serializers.ModelSerializer): # 用SerializerMethodField来获取该学生的所有课程 lectures = serializers.SerializerMethodField() def get_lectures(self, student_obj): # 通过Student的related_name拿到关联的StudentLecture,再取出对应的Lecture enrolled_lectures = student_obj.enrolled_lectures.all() return LectureSerializer([sl.lecture for sl in enrolled_lectures], many=True).data class Meta: model = Student fields = ('id', 'name', 'lectures') # 包含嵌套的lectures字段
情况二:返回单个选课记录,嵌套学生和课程的详情
如果你的接口是想返回某条StudentLecture记录,同时包含对应的学生和课程的完整信息,那序列化器可以这么写:
class StudentSerializer(serializers.ModelSerializer): class Meta: model = Student fields = ('id', 'name') class LectureSerializer(serializers.ModelSerializer): class Meta: model = Lecture fields = ('id', 'title', 'teacher') class StudentLectureNestedSerializer(serializers.ModelSerializer): # 直接嵌套学生和课程的序列化器 student = StudentSerializer() lecture = LectureSerializer() class Meta: model = StudentLecture fields = ('id', 'student', 'lecture', 'enroll_date')
3. 修改视图逻辑,返回嵌套结构而非平级列表
你的接口路径是/studentlectures/1/get_studlect/,这里的pk=1如果是学生ID,那视图可以这么写:
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.exceptions import NotFound from .models import Student from .serializers import StudentWithLecturesSerializer class StudentLectureDetailView(APIView): def get(self, request, pk): try: student = Student.objects.get(pk=pk) except Student.DoesNotExist: raise NotFound(detail="学生不存在") serializer = StudentWithLecturesSerializer(student) return Response(serializer.data)
如果pk=1是StudentLecture的ID,那视图调整为:
from .models import StudentLecture from .serializers import StudentLectureNestedSerializer class StudentLectureDetailView(APIView): def get(self, request, pk): try: stud_lect = StudentLecture.objects.get(pk=pk) except StudentLecture.DoesNotExist: raise NotFound(detail="选课记录不存在") serializer = StudentLectureNestedSerializer(stud_lect) return Response(serializer.data)
4. 验证返回结果
调整后,情况一的接口会返回:
{ "id": 1, "name": "张三", "lectures": [ { "id": 1, "title": "数学导论", "teacher": "李老师" }, { "id": 2, "title": "计算机基础", "teacher": "王老师" } ] }
情况二的接口会返回:
{ "id": 1, "student": { "id": 1, "name": "张三" }, "lecture": { "id": 1, "title": "数学导论", "teacher": "李老师" }, "enroll_date": "2024-05-20T14:30:00Z" }
如果你的实际模型或者期望的嵌套格式和上面不一样,把你的模型、序列化器、视图代码贴出来,我再帮你精准修改!
内容的提问来源于stack exchange,提问作者RaphaelDP
相关产品推荐
相关产品推荐

