Задать вопрос
sergey_1990
@sergey_1990
1

Как решить ошибку object has no attribute '_save_kwargs' при использовании PolymorphicSerializer + WritableNestedModelSerializer?

class Lesson(models.Model):


class Block(PolymorphicModel):

    BLOCK_TYPES = (
        # Обязательно имена дочерних моделей связанных с этой для поля resource_type в сериализаторе
        ('InfoBlock', 'Информация'),
        ('ConditionBlock', 'Условие'),
        ('QuizBlock', 'Опрос'),
    )

    lesson = models.ForeignKey(
        Lesson,  on_delete=models.CASCADE, related_name='blocks', null=True, blank=True)


class InfoBlock(Block):
    """информационный блок"""
    sortId = models.PositiveSmallIntegerField(
        default=1, verbose_name="Id сортировочный")
    transition = models.ForeignKey(Block, null=True, blank=True,  on_delete=models.CASCADE,
                                      related_name='infoBlocks',
                                      verbose_name="Блок на который осужествляется переход")

    class Meta:
        verbose_name = "Информационный блок"
        verbose_name_plural = "Информационные блоки"


class ConditionBlock(Block):
    """Блок условие"""
    sortId = models.PositiveSmallIntegerField(
        default=2, verbose_name="Id сортировочный")
    question = models.CharField(max_length=150, verbose_name='Куда дальше?')

    class Meta:
        verbose_name = "Блок условие"
        verbose_name_plural = "Блоки условие"

class ConditionBlockAnswer(models.Model):
    """"Ответы для блока условие"""
    block = models.ForeignKey(
        ConditionBlock, on_delete=models.CASCADE,  null=True, blank = True, related_name='answers')
    label = models.CharField(max_length=150, verbose_name='Ответ')
    transition = models.ForeignKey(Block, null=True, blank=True, on_delete=models.CASCADE, related_name='conditionBlocktransition',
                                      verbose_name="Блок на который осужествляется переход")

    class Meta:
        verbose_name = "Ответ к блоку условие"
        verbose_name_plural = "Ответы к блоку условие"


class QuizBlock(Block):

    """Блок вопрос"""
    sortId = models.PositiveSmallIntegerField(
        default=3, verbose_name="Id сортировочный")

    isShowResult = models.BooleanField(
        default=True, verbose_name='Показывать результат ответа')

    transitionRight = models.ForeignKey(Block,  on_delete=models.CASCADE, null=True, blank=True,
                                           related_name='quizBlockTransitionRight',
                                           verbose_name="Блок на который осужествляется переход Правильно")

    transitionError = models.ForeignKey(Block,  on_delete=models.CASCADE, null=True, blank=True,
                                           related_name='quizBlockTransitionError',
                                           verbose_name="Блок на который осужествляется переход Ошибка")

    class Meta:
        verbose_name = "Блок вопрос"
        verbose_name_plural = "Блоки вопросов"


class Quiz(models.Model):
    """"Вопросы для блока вопроса"""
    block = models.OneToOneField(
        QuizBlock, on_delete=models.CASCADE,  null=True, blank = True, related_name='quiz')


class QuizBlockQuestion(models.Model):
    """"Вопросы для блока вопроса"""
    quiz = models.ForeignKey(
        Quiz, on_delete=models.CASCADE,  null=True, blank = True, related_name='questions')

    label = models.CharField(max_length=150, verbose_name='Название вопроса')
    isMultiply = models.BooleanField(
        default=False, verbose_name='Множественный вариант ответов')

    class Meta:
        verbose_name = "Вопрос к блоку вопрос"
        verbose_name_plural = "Вопросы к блоку вопрос"
    
    def __str__(self):
        return self.label


class QuizBlockQuestionAnswer(models.Model):
    """"Ответы для каждого вопроса из блока вопрос"""
    question = models.ForeignKey(
        QuizBlockQuestion, on_delete=models.CASCADE,  null=True, blank = True, related_name='answers')
    label = models.CharField(max_length=150, verbose_name='Ответ')
    isRight = models.BooleanField(
        default=False, verbose_name='Правильно/Неправильно')

    class Meta:
        verbose_name = "Ответ к вопросу блока вопрос"
        verbose_name_plural = "Ответы к вопросу блока вопрос"

и сериализаторы:
class BlockSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
    class Meta:
        model = Block
        fields = '__all__'


##############################БЛОК информации########################
class InfoBlockSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
    files = FileSerializer(many=True, allow_null=True, required=False)
    videos = serializers.StringRelatedField(many=True, allow_null=True, required=False)
    audios = serializers.StringRelatedField(many=True, allow_null=True, required=False)
    images = ImageSerializer(many=True, allow_null=True, required=False)

    class Meta:
        model = InfoBlock
        exclude = ('polymorphic_ctype',)


######################################################################


#########################БЛОК УСЛОВИЕ#################################
class ConditionBlockAnswerSerializer(serializers.ModelSerializer):
    class Meta:
        model = ConditionBlockAnswer
        fields = '__all__'


class ConditionBlockSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
    answers = ConditionBlockAnswerSerializer(many=True)
    id = serializers.IntegerField(read_only=True)
    files = FileSerializer(many=True, allow_null=True, required=False)
    videos = serializers.StringRelatedField(many=True, allow_null=True, required=False)
    audios = serializers.StringRelatedField(many=True, allow_null=True, required=False)
    images = ImageSerializer(many=True, allow_null=True, required=False)

    class Meta:
        model = ConditionBlock
        exclude = ('polymorphic_ctype',)


#######################################################################


######################БЛОК ВОПРОС###################################
class QuizBlockQuestionAnswerSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
    class Meta:
        model = QuizBlockQuestionAnswer
        fields = '__all__'


class QuizBlockQuestionSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
    answers = QuizBlockQuestionAnswerSerializer(many=True)

    class Meta:
        model = QuizBlockQuestion
        fields = '__all__'


class QuizSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
    questions = QuizBlockQuestionSerializer(many=True)
    class Meta:
        model = Quiz
        exclude = ('block',)


class QuizBlockSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
    files = FileSerializer(many=True, allow_null=True, required=False)
    videos = serializers.StringRelatedField(many=True, allow_null=True, required=False)
    audios = serializers.StringRelatedField(many=True, allow_null=True, required=False)
    images = ImageSerializer(many=True, allow_null=True, required=False)
    quiz = QuizSerializer()

    class Meta:
        model = QuizBlock
        exclude = ('polymorphic_ctype',)


######################################################################


class BlockPolymorphicSerializer(PolymorphicSerializer, WritableNestedModelSerializer):

    resource_type_field_name = 'type'
    """основной полиморфный сериализатор блоков"""
    model_serializer_mapping = {
        Block: BlockSerializer,
        InfoBlock: InfoBlockSerializer,
        ConditionBlock: ConditionBlockSerializer,
        QuizBlock: QuizBlockSerializer,
    }

    class Meta:
        model = Block
        fields = '__all__'


class LessonSerializer(WritableNestedModelSerializer, serializers.ModelSerializer):
    """основной сериализатор уроков"""
    # при PUT обязательно ставить ID в блоках, иначе id изменится
    blocks = BlockPolymorphicSerializer(many=True)

    class Meta:
        model = Lesson
        fields = '__all__'

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        representation['blocksCount'] = instance.blocks.count()

        return representation

скинул всё чтоб понимание было, так вот в чём вопрос, если запускаю сериализатор LessonSerializer, то всё нормально сохраняется и отрабатывает, но встала необходимость корректировать отдельно блоки и казалось запуск сериализатора BlockPolymorphicSerializer и всё, но летит ошибка
File "/home/sergey/projects/kviliti/back-drf/venv/lib/python3.10/site-packages/drf_writable_nested/mixins.py", line 235, in _get_save_kwargs
save_kwargs = self._save_kwargs[field_name]
AttributeError: 'QuizBlockSerializer' object has no attribute '_save_kwargs'
причём она идёт только если наследники имеют вложенность, нагуглить удалось только 1 статью но не сработало https://github.com/beda-software/drf-writable-nest... если кто сталкивался прошу помочь, если в лоб перед строкой ошибки поставить self._save_kwargs = defaultdict(dict) то ошибка пропадает, но ето же не дело лезть в пакет
  • Вопрос задан
  • 80 просмотров
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы