Django Rest:使用M2M模型

时间:2016-10-07 11:46:44

标签: python django django-rest-framework

我有一个简单的关系结构,项目包含几个带有中间元模型的序列。

我可以轻松地执行GET请求并正确格式化数据。但是,当我想发布validated_data变量时,不包含正确格式化的数据,所以我无法编写创建/更新方法。

数据应如下所示:

{'name': 'something', 
'seqrecords': [{
                'id': 5, 
                'sequence': 'ACGG...AAAA', 
                'name': 'Z78529',
                'order': 1
               },
               {
                'id': 6,
                'sequence': 'CGTA...ACCC',
                'name': 'Z78527',
                'order': 2
               }, 
}

但它看起来像这样:

{'name': 'something',
 'projectmeta_set': [
                     OrderedDict([('order', 1)]),
                     OrderedDict([('order', 2)]),
                     OrderedDict([('order', 3)])
                    ]
}

串行器:

class ProjectMetaSerializer(serializers.HyperlinkedModelSerializer):
    id = serializers.ReadOnlyField(source='sequence.id')
    name = serializers.ReadOnlyField(source='sequence.name')

    class Meta:
        model = ProjectMeta
        fields = ['id', 'name', 'order']


class ProjectSerializer(serializers.HyperlinkedModelSerializer):
    seqrecords = ProjectMetaSerializer(source='projectmeta_set', many=True)

    class Meta:
        model = Project
        fields = ['id', 'name', 'seqrecords']
        ReadOnlyField = ['id']

    def create(self, validated_data):
        project = Project(name=validated_data['name'])
        project.save()
        # This is where it all fails
        for seq in validated_data['seqrecords']:
            sequence = SeqRecord.objects.filter(id=seq['id'])
            meta = ProjectMeta(project=project,
                               sequence=sequence,
                               order=seq['order'])
            meta.save()
        return project

class SeqRecordSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = SeqRecord
        fields = ['id', 'name', 'sequence']
        read_only_fields = ['id']

型号:

class SeqRecord(models.Model):
    name = models.CharField(max_length=50)
    sequence = models.TextField()


class Project(models.Model):
    name = models.CharField(max_length=50)
    sequences = models.ManyToManyField(SeqRecord,
                                       through='primer_suggestion.ProjectMeta')


class ProjectMeta(models.Model):
    project = models.ForeignKey(Project)
    sequence = models.ForeignKey(SeqRecord)
    order = models.PositiveIntegerField()

查看

class ProjectApiList(viewsets.ViewSetMixin, generics.ListCreateAPIView):
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer

有没有办法改变数据的验证,所以它返回我需要的东西,或者我可以用其他方式编写创建和函数?

2 个答案:

答案 0 :(得分:0)

正如您在ProjectMetaSerializer中看到的,字段idname是ReadOnlyFields。因此,您无法在post请求中使用它们。

class ProjectMetaSerializer(serializers.ModelSerializer):
    seqrecords = SeqRecordSerializer(many=True)

    class Meta:
        model = ProjectMeta
        fields = ['seqrecords',]


class ProjectSerializer(serializers.ModelSerializer):
    project_meta = ProjectMetaSerializer(many=True)

    class Meta:
        model = Project
        fields = ['id', 'name', 'project_meta']
        ReadOnlyField = ['id']

def create(self, validated_data):
    project = Project(name=validated_data['name'])
    project.save()
    # This is where it all fails
    for seq in validated_data['seqrecords']:
        sequence = SeqRecord.objects.filter(id=seq['id'])
        meta = ProjectMeta(project=project,
                           sequence=sequence,
                           order=seq['order'])
        meta.save()
    return project

class SeqRecordSerializer(serializers.ModelSerializer):
    class Meta:
        model = SeqRecord
        fields = ['id', 'name', 'sequence']

答案 1 :(得分:0)

要返回正确的数据格式,可以在ProjectSerializer中覆盖函数“to_internal”,如下所示:

class ProjectSerializer(serializers.HyperlinkedModelSerializer):
    seqrecords = ProjectMetaSerializer(source='projectmeta_set', many=True)

    class Meta:
        model = Project
        fields = ['id', 'name', 'seqrecords']
        ReadOnlyField = ['id']

    def to_internal_value(self, data):
        ''' Override standard method so validated data have seqrecords '''
        context = super(ProjectSerializer, self).to_internal_value(data)
        context['seqrecords'] = data['seqrecords']

        return context

    def validate(self, data):
        ...

    def create(self, validated_data):
        ...
        return project

此方法当然取决于validate()中“seqrecords”字段的良好验证功能。

相关问题