Сериализация отношений в django

#python #django #django-rest-framework

#python #django #django-rest-framework

Вопрос:

У меня есть 2 модели -> Кандидат и оценка. У 1 кандидата много оценок. Я хочу вернуть из rest API среднюю оценку из многих оценок, которые может получить один кандидат. Как я могу это сделать.

Моя модель:

 class Candidate(models.Model):
   first_name = models.CharField(max_length=50)
   last_name = models.CharField(max_length=50)

class Grade(models.Model):
   value = models.IntegerField(blank=True, null=True)
   candidate = models.ForeignKey(Candidate, on_delete=models.CASCADE, related_name='grades') 
  

Мой serializers.py

 from rest_framework import serializers
from .models import Candidate, Grade


class CandidateSerializer(serializers.ModelSerializer):

   pk = serializers.SerializerMethodField('get_pk_from_candidate')
   full_name = serializers.SerializerMethodField('get_full_name_from_candidate')
   grades = serializers.SlugRelatedField(many=True, read_only=True, slug_field='value')
   
   class Meta: 
    
      model = Candidate
 
      fields = ['pk', 'full_name', 'avg_grade', 'grades']

  
   def get_pk_from_candidate(self, candidate):
      return candidate.id

   
   def get_full_name_from_candidate(self, candidate):
      data = (candidate.first_name, candidate.last_name)
      full_name = ' '.join(data)

      return full_name
  

Я хочу, чтобы мой формат JSON выглядел следующим образом:

 {
      "pk": 3,
      "full_name": "rafał małek",
      "avg_grade": "",
      "grades": [
        12,
        4,
        13,
        5
      ]
    },
  

Комментарии:

1. Я попытался написать метод, в котором я могу вычислить среднее значение, но я не знаю, как обрабатывать в этом методе массив моих оценок

Ответ №1:

Вы можете использовать SerializerMethodField() и агрегацию ORM (doc) с помощью Avg.

 from django.db.models import Avg
from rest_framework import serializers
from .models import Candidate, Grade


class CandidateSerializer(serializers.ModelSerializer):
   pk = serializers.SerializerMethodField('get_pk_from_candidate')
   full_name = serializers.SerializerMethodField('get_full_name_from_candidate')
   avg_grade = serializers.SerializerMethodField('get_avg_grade')
   grades = serializers.SlugRelatedField(many=True, read_only=True, slug_field='value')
   
   class Meta: 
      model = Candidate
      fields = ['pk', 'full_name', 'avg_grade', 'grades']

  
   def get_pk_from_candidate(self, candidate):
      return candidate.id

   
   def get_full_name_from_candidate(self, candidate):
      data = (candidate.first_name, candidate.last_name)
      full_name = ' '.join(data)

      return full_name

   def get_avg_grade(self, candidate):
       return candidate.grades.aggregate(Avg('value'))['value__avg']
  

Ответ №2:

Использовать serializers.SerializerMethodField как

 
from django.db.models import Avg


class CandidateSerializer(serializers.ModelSerializer):
    pk = serializers.SerializerMethodField('get_pk_from_candidate')
    full_name = serializers.SerializerMethodField('get_full_name_from_candidate')
    grades = serializers.SlugRelatedField(many=True, read_only=True, slug_field='value')
    avg_grade = serializers.SerializerMethodField()

    def get_avg_grade(self, candidate):
        return candidate.grades.aggregate(avg_value=Avg('value')).get("avg_value")

    class Meta:
        model = Candidate

        fields = ['pk', 'full_name', 'avg_grade', 'grades']

    def get_pk_from_candidate(self, candidate):
        return candidate.id

    def get_full_name_from_candidate(self, candidate):
        data = (candidate.first_name, candidate.last_name)
        full_name = ' '.join(data)

        return full_name