Как сделать вложенный сериализатор доступным внутри create() ModelSerializer, не делая вложенный сериализатор read_only=False

У меня небольшая дилемма. Задача состоит в том, чтобы принять json, содержащий некоторую информацию о помёте кроликов и родившихся крольчатах. У меня есть ThrowInfoSerializer с моделью Throw (Throw = Litter, не англоязычная страна). Внутри create ThrowInfoSerializer я хочу сохранить новый помет и соответствующих новых кроликов, поэтому я вызываю new_bunnies = validated_data.pop('new_bunnies') и хочу извлечь данные о новых кроликах из validated_data.

Проблема в том, что поскольку новые данные Bunny хранятся в другом ModelSerializer, который связан с моделью Bunny, и является BunnySerializer(many=True, read_only=True) read_only, то они не доступны в validated_data внутри create().

Но если я хочу сделать new_bunnies read_only=False, чтобы информация стала частью validated_data внутри create(), я получаю эту ошибку:

AttributeError: Got AttributeError when attempting to get a value for field `new_bunnies` on serializer `ThrowInfoSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Throw` instance.
Original exception text was: 'Throw' object has no attribute 'new_bunnies'.

Что вполне логично, поскольку ThrowInfoSerializer привязан к Throw Model.

Я не могу сделать еще один сериализатор и поместить ThrowInfoSerializer и BunnySerializers на один уровень, поскольку мне все еще нужна Throw Info из ThrowInfoSerializer для сохранения новых кроликов.

Throw = Litter, мы испортили перевод

Вот код: Serializers.py

from rest_framework import serializers
from rest_framework.serializers import Serializer, ModelSerializer, SerializerMethodField

from bunny_service.bunny_utils import getStudBookKeeperOfUser
from bunny_service.models import Throw, Bunny

class BunnySerializer(ModelSerializer):
    sex = serializers.CharField()
    class Meta:
        model = Bunny
        fields = ['sex', 'RID', 'COLID']

class ParentBunnySerializer(ModelSerializer):
    class Meta:
        model = Bunny
        fields = ['RID', 'COLID', 'l_ear', 'r_ear', 'UID_owner']

    def validate(self, attrs):
         # Check if a Bunny with the given attributes exists
        if not Bunny.objects.filter(
                RID=attrs.get('RID'),
                COLID=attrs.get('COLID'),
                l_ear=attrs.get('l_ear'),
                r_ear=attrs.get('r_ear'),
                UID_owner=attrs.get('UID_owner')
        ).exists():
            raise serializers.ValidationError("A bunny with those properties does not exist")
        return attrs


class ThrowInfoSerializer(ModelSerializer):
    count = SerializerMethodField()
    remaining = SerializerMethodField()
    new_bunnies = BunnySerializer(many=True)


    BID_buck = ParentBunnySerializer()
    BID_doe = ParentBunnySerializer()

    class Meta:
        model = Throw
        fields = ['thrown_on', 'covered_on', 'death_count', 'BID_buck', 'BID_doe', 'count', 'remaining', 'new_bunnies']

    def get_count(self, instance):
        return instance.bunny_set.count()

    def get_remaining(self, instance):
        return self.get_count(instance) - instance.death_count

    def create(self, validated_data, **kwargs):
        print(validated_data)
        new_bunnies = validated_data.pop('new_bunnies')

        BID_buck = Bunny.objects.get(**validated_data.pop('BID_buck', None))
        BID_doe = Bunny.objects.get(**validated_data.pop('BID_doe', None))

        validated_data['BID_buck'] = BID_buck
        validated_data['BID_doe'] = BID_doe
        validated_data['UID_stud_book_keeper'] = getStudBookKeeperOfUser(self.context['user'])

        throw = Throw.objects.create(**validated_data)

        print(new_bunnies)
        for bunny in new_bunnies:
            Bunny.objects.create(
                **bunny,
                TID=throw,
                UID_owner=self.context['user'],
                CID=self.context['user'].CID_breeding_club,
                l_ear="TO BE IMPLEMENTED", #TODO: implement
                r_ear="TO BE IMPLEMENTED"
            )

        print(Bunny.objects.all())
        return throw

models.py

Надеюсь, это имеет смысл

Ошибка, которую вы получаете Original exception text was: 'Throw' object has no attribute 'new_bunnies'., связана с тем, что поля с именем new_bunnies на самом деле не существует. Чтобы исправить это, вы можете:

  • Измените new_bunnies на название поля, которое реально существует в модели.

  • Укажите, на какое поле new_bunny ссылается:

new_bunnies = UUIDField(source='the.referenced.field.in.the.model)

В случае необходимости навигации по отношениям в исходном поле, разделяйте их точками .. И, конечно же, замените UUIDField на тип поля, который соответствует данным, которые вы собираетесь получить.

  • Или, если new_bunnies не является полем конкретной модели, вы можете просто определить его, как во втором варианте, но без поля source.
new_bunnies = UUIDField()

Таким образом вы определяете поле для сериализатора, хотя в модели его не существует. Но при таком подходе вам понадобится пользовательская функция create() для обработки того, что происходит с этим новым полем, поскольку оно не является частью модели и django не будет знать, что с ним делать.

Надеюсь, это поможет вам.

Вернуться на верх