【问题标题】:How to get list elements from manytomany field in Django Rest Framework serializer如何从 Django Rest Framework 序列化程序中的 manytomany 字段中获取列表元素
【发布时间】:2018-03-18 14:03:23
【问题描述】:

遵循 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))

GroupSerializer.create() 方法中带有#DEBUG 的两行在终端中打印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 QueryDict 具有带有所有 dict 元素的 'inclusion_criteria': ["{'code': 'A00'}", "{'code': 'A1782'}", "{'code': 'A3681'}", "{'code': 'A74'}"],为什么 self.initial_data['inclusion_criteria'] 只获得最后一个术语 ({'code': 'AY4'}) 而不是全部?

我错过了什么?

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    我找到了缺失的部分。使用 APITestCase 类发布嵌套对象时,需要选择正确的数据类型。

    如果您在未指定数据格式的情况下发布,则您发布 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-24
      • 2014-01-05
      • 2020-06-16
      • 2021-12-26
      • 2016-10-03
      • 2013-11-15
      • 1970-01-01
      相关资源
      最近更新 更多