如何从Django Rest Framework序列化器中的manytomany字段获取列表元素

时间:2017-10-06 17:44:27

标签: python django django-rest-framework

遵循Django REST框架docs从测试客户端发布时,我无法获得dict嵌套字段。

我的模特是:

class ClassificationOfDiseases(models.Model):
    code = models.CharField(max_length=10)
    description = models.CharField(max_length=300)
    abbreviated_description = models.CharField(max_length=190)
    parent = models.ForeignKey('self', null=True, related_name='children')

    def __str__(self):
        return self.abbreviated_description

class Group(models.Model):
    experiment = models.ForeignKey(Experiment, related_name='groups')
    title = models.CharField(max_length=50)
    description = models.TextField()
    inclusion_criteria = \
        models.ManyToManyField(ClassificationOfDiseases, blank=True)
    protocol_component = models.ForeignKey(
        ProtocolComponent, null=True, blank=True
    )

该模型的序列化器是:

class ClassificationOfDiseasesSerializer(serializers.Serializer):
    class Meta:
        model = ClassificationOfDiseases
        fields = ('code',)


class GroupSerializer(serializers.ModelSerializer):
    experiment = serializers.ReadOnlyField(source='experiment.title')
    inclusion_criteria = ClassificationOfDiseasesSerializer(many=True,
                                                            read_only=False)

    class Meta:
        model = Group
        fields = ('id', 'title', 'description', 'experiment',
                  'inclusion_criteria')

    def create(self, validated_data):
        group = Group.objects.create(experiment=validated_data['experiment'],
                                     title=validated_data['title'],
                                     description=validated_data['description'])
        if 'inclusion_criteria' in self.initial_data:
            inclusion_criteria = self.initial_data['inclusion_criteria']
            print(inclusion_criteria)  # DEBUG
            print(self.initial_data)  # DEBUG
            for criteria in inclusion_criteria:
                classification_of_diseases = \
                    ClassificationOfDiseases.objects.filter(
                        code=criteria['code']
                    )
                if classification_of_diseases:
                    group.inclusion_criteria.add(
                        classification_of_diseases.first()
                    )
        return group

并且,测试将数据发布到API,如下所示:

def test_POSTing_new_group_adds_pre_existent_classification_of_diseases(self):
    owner = User.objects.get(username='lab1')
    experiment = Experiment.objects.get(nes_id=1, owner=owner)
    self.client.login(username=owner.username, password='nep-lab1')
    list_url = reverse('api_experiment_groups-list',
                       kwargs={'experiment_nes_id': experiment.nes_id})
    response = self.client.post(
        list_url,
        {
            'title': 'A title',
            'description': 'A description',
            # we post inclusion_criteria's that exists in
            # ClassificationOfDiseases table (this table is
            # pre-populated in db)
            'inclusion_criteria': [
                {'code': 'A00'}, {'code': 'A1782'}, {'code': 'A3681'},
                {'code': 'A74'}
            ]
        }
    )
    self.assertEqual(response.status_code, status.HTTP_201_CREATED)
    self.client.logout()
    new_group = Group.objects.last()
    for inclusion_criteria in new_group.inclusion_criteria_set:
        self.assertEqual(inclusion_criteria,
                         ClassificationOfDiseases.objects.get(
                             code=inclusion_criteria))

#DEBUG方法中GroupSerializer.create()的两行在终端中打印inclusion_criteriaself.initial_data。输出分别为:

{'code': 'A74'}   # print(inclusion_criteria)
<QueryDict: {'inclusion_criteria': ["{'code': 'A00'}", "{'code': 'A1782'}", "{'code': 'A3681'}", "{'code': 'A74'}"], 'title': ['A title'], 'description': ['A description']}>  # print(self.initial_data)

那么,为什么self.initial_data['inclusion_criteria']只获得最后一个词({'code': 'AY4'})而不是所有词,如果self.initial_data QueryDict有'inclusion_criteria': ["{'code': 'A00'}", "{'code': 'A1782'}", "{'code': 'A3681'}", "{'code': 'A74'}"]所有dict元素?

我失踪了什么?

1 个答案:

答案 0 :(得分:0)

我有缺失的部分。使用API​​TestCase类发布嵌套对象时,需要选择正确的数据类型。

如果您在未指定数据格式的情况下发布,那么您发布QueryDict的APITestCase.client.post方法,就是我在print(inclusion_criteria)声明中所获得的内容。

<QueryDict: {'inclusion_criteria': ["{'code': 'A00'}", "{'code': 'A1782'}", "{'code': 'A3681'}", "{'code': 'A74'}"], 'title': ['A title'], 'description': ['A description']}>

我们需要以json格式发布数据,因此我们将format=json作为第三个参数传递给APITestCase.client.post方法。

所以,我们使用:

response = self.client.post(
            list_url,
            {
                'title': 'A title',
                'description': 'A description',
                'inclusion_criteria': [
                    {'code': 'A00'}, {'code': 'A1782'}, {'code': 'A3681'},
                    {'code': 'A74'}
                ]
            }, format='json'
        )

感谢此stackoverflow post