Избегайте вложенных объектов при использовании вложенных сериализаторов - PullRequest
0 голосов
/ 14 октября 2019

У меня есть две модели, одна содержит другую в отношении ForeignKey, я хотел создать API, который бы возвращал объединение этих двух моделей, поэтому я попытался использовать вложенные Serializer для добавления связанной модели, ноданные не все на одном уровне, связанные модели - это объекты внутри первого.

Вот модели

class ModelOne(models.Model):
    last_counter = models.IntegerField()


class ModelTwo(models.Model):
    model_one = models.ForeignKey(ModelOne, on_delete=models.CASCADE)
    category = models.CharField(max_length=64)
    counter_type = models.CharField(max_length=32)

Вот сериализаторы

class ModelOneSerializer(serializers.ModelSerializer):
    class Meta:
        model = ModelOne
        fields = "__all__"


class ModelTwoSerializer(serializers.ModelSerializer):
    model_one= ModelOneSerializer(read_only=True)

    class Meta:
        model = ModelTwo
        fields = "__all__"

Это будет возвращаться из API в виде

{
   "category" : ...,
   "counter_type" : ...,
   "model_one" : {
     "last_counter" : ...
   }
}

Но я не хочу, чтобы ответ был таким, я хочу, чтобы он был больше похож на это

{
   "category" : ...,
   "counter_type" : ...,
   "last_counter" : ...,
}

Есть ли способ добиться этого с помощью сериализаторов?

Ответы [ 2 ]

1 голос
/ 15 октября 2019

Вы можете добиться того, что хотите сделать, используя SerializerMethodField из полей drf:

SerializerMethodField - это поле только для чтения, которое вычисляет свое значение во время обработки запроса, вызывая метод в классе сериализатора, к которому он присоединен. к. Например, для вашего случая это будет выглядеть так. Обратите внимание, что вычисленный last_counter добавляется в поля сериализованной модели.

from rest_framework.fields import SerializerMethodField

class ModelTwoSerializer(serializers.ModelSerializer):
    last_counter = serializers.SerializerMethodField()

class Meta:
    model = ModelTwo
    fields = ["category", "counter_type", "last_counter"]

def get_last_counter(self, obj):
    return int(obj.model_one.last_counter)

SerializerMethodField принимает method_name, но обычно более удобно использовать шаблон по умолчанию для именования этих методов, который называется get_. Просто убедитесь, что вы не перегружаете поля вашего метода какими-либо тяжелыми операциями.

Вы можете прочитать больше в официальной документации: введите описание ссылки здесь

1 голос
/ 15 октября 2019

Использовать SerializerMethodField

from rest_framework.fields import SerializerMethodField

class ModelTwoSerializer(serializers.ModelSerializer):
    last_counter = SerializerMethodField()

    class Meta:
        model = ModelTwo
        fields = "__all__"

    def get_last_counter(self, obj):
        return ModelOneSerializer(obj.model_one).data['last_counter']

При создании настраиваемых полей (например, field_one) с помощью SerializerMethodField необходимо создать метод с именем get_field_one, чтобы этот метод был автоматически обнаруженпо сериализатору.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...