Django自定义序列化器:如何从关联模型添加字段?
问题:Django REST Framework序列化器如何添加关联模型的字段?
我现在有这样的Django模型定义:
class Subject(models.Model): db = 'default' subjectName = models.CharField(max_length = 100) cohortID = models.ForeignKey(Cohort, on_delete=models.CASCADE, related_name='subjects') teacherID = models.ForeignKey(Teacher, on_delete=models.CASCADE, related_name='subjects', null=True) class Cohort(models.Model): db = 'default' school_creator = models.ForeignKey(CustomUser, on_delete = models.CASCADE, related_name='cohorts') mainTeacherID = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=True, related_name='mainCohorts') class_name = models.CharField(max_length = 100)
当前使用的Subject序列化器是:
class SubjectSerializer(serializers.ModelSerializer): class Meta: model = models.Subject fields = ('subjectName', 'teacherID', 'pk',)
它返回的结果是:
{"subjectName":"Maths","teacherID":2,"pk":4}
我希望返回结果里能包含关联的Cohort模型的class_name字段,命名为cohortName,也就是要得到这样的结构:
{"subjectName":"Maths","teacherID":2,"pk":4, "cohortName" : "4 B"}
我尝试自定义了下面的序列化器,但运行出错,没法实现需求,求指点:
class SubjectCohortSerializer(serializers.ModelSerializer): cohortName = serializers.SerializerMethodField(read_only=True) class Meta: model = models.Subject fields = ('subjectName', 'teacherID', 'pk','cohortName') def get_cohortName(self, subject): return models.Cohort.objects.get(pk=self.context['request'].cohortID.className)
错误分析
你写的get_cohortName方法有两个明显问题:
- 完全没必要额外查询数据库——
Subject模型已经通过cohortID外键关联到Cohort,直接通过当前的subject对象就能访问关联的Cohort实例,不用重新查库; self.context['request'].cohortID.className写法完全错误:请求对象里没有cohortID这个属性,而且模型里的字段名是class_name,不是className。
正确解法
这里有两种简单的实现方式,选哪种都可以:
方法1:使用SerializerMethodField(最灵活)
修改你的自定义序列化器,直接从当前subject对象获取关联Cohort的class_name:
class SubjectCohortSerializer(serializers.ModelSerializer): cohortName = serializers.SerializerMethodField(read_only=True) class Meta: model = models.Subject fields = ('subjectName', 'teacherID', 'pk','cohortName') def get_cohortName(self, subject): # 直接通过外键关联访问Cohort实例的class_name字段 return subject.cohortID.class_name
方法2:使用SlugRelatedField(更简洁)
如果只是想获取关联模型的某个字段值,用SlugRelatedField更直接,不需要写额外的方法:
class SubjectCohortSerializer(serializers.ModelSerializer): cohortName = serializers.SlugRelatedField( source='cohortID', read_only=True, slug_field='class_name' ) class Meta: model = models.Subject fields = ('subjectName', 'teacherID', 'pk','cohortName')
这两种方法都能得到你想要的返回结构,要是担心性能,可以在查询Subject时加上select_related('cohortID')做预查询,减少数据库请求次数。
内容的提问来源于stack exchange,提问作者Iskender Berdiev
相关产品推荐
相关产品推荐

