如何在DRF中获取序列化器类的计算属性?
解决Django序列化器中无法调用其他SerializerMethodField属性的问题
你的问题核心在于:SerializerMethodField对应的字段值并不是序列化器实例的属性,它是在序列化过程中通过调用get_*方法动态计算的,所以直接用self.students_count访问会触发AttributeError。以下是几种可行的解决方法:
方法一:直接调用对应的get_*方法
既然students_count是由get_students_count方法计算的,直接在get_demand_course_percent里调用这个方法即可,既复用已有逻辑,又避免重复代码:
def get_demand_course_percent(self, obj) -> int: users = CustomUser.objects.all().count() students = self.get_students_count(obj) return (students / users) * 100
方法二:重写to_representation统一计算依赖字段
如果多个字段之间存在依赖关系,可以重写序列化器的to_representation方法,提前计算所有需要的字段值,再组装返回结果:
class CourseSerializer(serializers.ModelSerializer): lessons = MiniLessonSerializer(many=True, read_only=True) # 只声明字段,不单独写get_*方法 lessons_count = serializers.IntegerField(read_only=True) students_count = serializers.IntegerField(read_only=True) groups_filled_percent = serializers.IntegerField(read_only=True) demand_course_percent = serializers.IntegerField(read_only=True) def get_lessons_count(self, obj) -> int: return obj.lessons.count() def get_students_count(self, obj) -> int: return Subscription.objects.filter().count() def get_groups_filled_percent(self, obj) -> int: counts = [group.users.count() for group in obj.groups.all()] return ((sum(counts) / len(counts)) / 30) * 100 def to_representation(self, instance): # 提前计算所有需要的统计值 students_count = self.get_students_count(instance) demand_course_percent = (students_count / CustomUser.objects.all().count()) * 100 # 调用父类方法获取基础序列化数据,再补充自定义字段 data = super().to_representation(instance) data['students_count'] = students_count data['demand_course_percent'] = demand_course_percent data['lessons_count'] = self.get_lessons_count(instance) data['groups_filled_percent'] = self.get_groups_filled_percent(instance) return data
方法三:提取重复逻辑为私有方法
如果某个计算逻辑被多个字段复用,把它抽成序列化器的私有方法,供各个get_*方法调用:
class CourseSerializer(serializers.ModelSerializer): lessons = MiniLessonSerializer(many=True, read_only=True) lessons_count = serializers.SerializerMethodField(read_only=True) students_count = serializers.SerializerMethodField(read_only=True) groups_filled_percent = serializers.SerializerMethodField(read_only=True) demand_course_percent = serializers.SerializerMethodField(read_only=True) def _get_total_students(self) -> int: # 抽取出核心计算逻辑 return Subscription.objects.filter().count() def get_lessons_count(self, obj) -> int: return obj.lessons.count() def get_students_count(self, obj) -> int: return self._get_total_students() def get_groups_filled_percent(self, obj) -> int: counts = [group.users.count() for group in obj.groups.all()] return ((sum(counts) / len(counts)) / 30) * 100 def get_demand_course_percent(self, obj) -> int: users = CustomUser.objects.all().count() return (self._get_total_students() / users) * 100
内容的提问来源于stack exchange,提问作者dasEgo
相关产品推荐
相关产品推荐

