带有PrimaryKeyRelatedField的可写嵌套序列化程序

时间:2017-09-04 15:12:59

标签: serialization nested django-rest-framework

我在为以下模型创建(嵌套)序列化程序时遇到问题:

class Chapter(Model):
    uuid = UUIDField(primary_key=True, editable=False)
    description = TextField(blank=True)

class Section(Model):
    uuid = UUIDField(primary_key=True, editable=False)
    description = TextField(blank=True)
    chapter = ForeignKey(Chapter, related_name='sections', on_delete=CASCADE)

以下是使用create方法的章节模型的序列化程序:

class ChapterSerializer(ModelSerializer):
    uuid = UUIDField(read_only=False)
    sections = SectionSerializer(many=True, read_only=False)

    class Meta:
        model = Chapter
        fields = ('uuid', 'description', 'sections')

    def create(self, validated_data):
        sections = validated_data.pop('sections', [])
        chapter = Chapter.objects.create(**validated_data)

        for section in sections:
            section.update({'chapter': chapter})
            section = Section.objects.create(**section)

        return chapter

以下是Section序列化程序的两个略有不同的变体:

class SectionSerializer(ModelSerializer):
        uuid = UUIDField(read_only=False)
        chapter = PrimaryKeyRelatedField(read_only=true)

        class Meta:
            model = Section
            fields = ('uuid', 'description', 'chapter')

class SectionSerializer(ModelSerializer):
        uuid = UUIDField(read_only=False)
        chapter = PrimaryKeyRelatedField(queryset=Chapter.objects.all())

        class Meta:
            model = Section
            fields = ('uuid', 'description', 'chapter')

现在,如果我尝试创建一个带有嵌套Sections的新章节,并且Section序列化程序中的PrimaryKeyRelatedField设置了queryset参数,我会收到以下错误:

'sections': [{'chapter': ['Invalid pk "x" - object does not exist.']}]

如果我将变量与read_only=true参数一起使用,则创建一个带有嵌套Sections的新章节,但现在我不能再创建一个新的Section(章节字段设置为现有章节UUID),因为章节验证输入数据时删除字段。

django.db.utils.IntegrityError: null value in column "chapter_id" violates not-null constraint

我想我可以通过复制SectionSerializer来解决这个问题,但这似乎是一个非常粗糙的解决方案......

有人知道更好的方法吗?

2 个答案:

答案 0 :(得分:1)

好的,回答我自己的问题:

我终于找到了一种方法来获得一个可嵌套的"和#34;可写"没有代码重复的SectionSerializer的版本:

class NestedSectionSerializer(ModelSerializer):
    uuid = UUIDField(read_only=False)

    class Meta:
        model = Section
        exclude = ('chapter', )

class SectionSerializer(NestedSectionSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='section-detail')

    class Meta:
        model = Section
        fields = '__all__'

class ChapterSerializer(ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='chapter-detail')
    uuid = UUIDField(read_only=False)
    sections = NestedSectionSerializer(many=True, read_only=False)

    class Meta:
        model = Chapter
        fields = '__all__'

    def create(self, validated_data):
        sections = validated_data.pop('sections', [])
        chapter = Chapter.objects.create(**validated_data)

        for section in sections:
            section.update({'chapter': chapter})
            section = Section.objects.create(**section)

        return chapter

这里的关键是明确排除对#34;嵌套"中的chapter的崇敬。序列化程序,但在"可写"中再次添加它串行器。这甚至可以扩展到深层嵌套的结构!

通过使用继承,我可以避免大多数代码重复。

答案 1 :(得分:0)

我只是拉着我的头发讲述同样的问题。

答案实际上在DRF文档中:如果您希望它们可写,则需要明确定义PrimaryKeyRelatedField的queryset参数。

在您的情况下,只需要SectionSerializer的第二个变体。