验证期间丢失字段 - 嵌套序列化器 create()

And*_*ewO 5 django django-rest-framework

我不明白为什么特定字段会在 valid_data 中被删除。

当将输入发布到 create() 一个新实例时,以下行: thisLabel = ClassificationLabel.objects.get(identifier=label.identifier) 抛出错误,因为标识符属性不存在:

AttributeError at /api/v1/policies/ 
Run Code Online (Sandbox Code Playgroud)

'collections.OrderedDict' object has no attribute 'identifier

我在 Django REST 框架中有以下序列化器:

序列化器.py:

class ClassificationLabelDetailSerializer(serializers.ModelSerializer):

    class Meta:
        model = ClassificationLabel
        fields = ('displayName', 'helpText', 'identifier', 'backgroundColour', 'foregroundColour', 'comment', 'description', 'lastChanged', 'revision')
        read_only_fields = ('identifier', 'lastChanged', 'revision',)


class PolicySerializer(serializers.ModelSerializer):
    labels = ClassificationLabelDetailSerializer(many=True)

    class Meta:
        model = Policy
        fields = ('displayName', 'identifier', 'labels', 'lastChanged', 'description', 'comment')
        read_only_fields = ('identifier', 'lastChanged',)

    def create(self,validated_data):
        labelData = validated_data.pop('labels')
        thisPolicy = Policy.objects.create(**validated_data)
        for label in labelData:
            for k, v in label.items():
                print(k, v)
            thisLabel = ClassificationLabel.objects.get(identifier=label.identifier)#insert organisational filter here
            PolicyMemberClassificationLabel.objects.create(policy=thisPolicy, label=thisLabel, order=index)
        return thisPolicy
Run Code Online (Sandbox Code Playgroud)

模型.py:

class ClassificationLabel(models.Model):
    displayName = models.CharField(max_length = 32)
    helpText = models.TextField(max_length = 140, blank=True)
    backgroundColour = models.CharField(max_length=8)
    foregroundColour = models.CharField(max_length=8)
    description = models.TextField(max_length = 256, blank=True)
    comment = models.TextField(max_length = 1024, blank=True)
    lastChanged = models.DateTimeField(auto_now=True, editable=False)
    identifier = models.CharField(max_length = 128, blank=True, editable=False)
    revision = models.PositiveIntegerField(default=1, editable=False)

    def __str__(self):
        return self.displayName + " - " + self.identifier

    def save(self, *args, **kwargs):
        self.revision += 1
        #the following code generates a unique identifier and checks it for collisions against existing identifiers
        if not self.identifier:
            stringCheck = False
            while stringCheck is False:
                newString = str(uuid.uuid4())
                newString.replace('-', '')
                doesStringExist = ClassificationLabel.objects.filter(identifier=newString).exists()
                if doesStringExist is False:
                    stringCheck = True
            self.identifier = newString
        super(ClassificationLabel, self).save(*args, **kwargs) # Call the "real" save() method.


class Policy(models.Model):
    description = models.TextField(max_length = 256, blank=True)
    comment = models.TextField(max_length = 1024, blank=True)
    lastChanged = models.DateTimeField(auto_now =True)
    displayName = models.CharField(max_length = 64)
    identifier = models.CharField(max_length = 128, blank=True)
    labels = models.ManyToManyField(ClassificationLabel, through='PolicyMemberClassificationLabel')
    revision = models.PositiveIntegerField(default=1)

    class Meta:
        verbose_name_plural = 'Policies'

    def __str__(self):
        return self.displayName + " - " + self.identifier

    def save(self, *args, **kwargs):
        self.revision += 1
        #the following code generates a unique identifier and checks it for collisions against existing identifiers
        if not self.identifier:
            stringCheck = False
            while stringCheck is False:
                newString = str(uuid.uuid4())
                newString.replace('-', '')
                doesStringExist = Policy.objects.filter(identifier=newString).count()
                if doesStringExist == 0:
                    stringCheck = True
            self.identifier = newString
            super(Policy, self).save() # Call the "real" save() method.


class PolicyMemberClassificationLabel(models.Model):
    label = models.ForeignKey(ClassificationLabel, related_name='memberLabels')
    policy = models.ForeignKey(Policy, related_name='parentPolicy')
    order = models.PositiveSmallIntegerField(blank=True)
Run Code Online (Sandbox Code Playgroud)

当通过 POST 发送以下内容时,它会从 valid_data 中的嵌套表示中删除标识符、lastChanged 和修订字段。

{
  "labels": [
    {
      "displayName": "Test name",
      "helpText": "Wayfarers sartorial authentic, small batch readymade disrupt coloring book. Wayfarers sartorial authentic, small batch readymade disrupt col",
      "identifier": "fa27e9bd-5007-4874-b10c-46b63c7c8a86",
      "backgroundColour": "#808900",
      "foregroundColour": "#000000",
      "comment": "Wayfarers sartorial authentic, small batch readymade disrupt coloring book.",
      "description": "Wayfarers sartorial authentic, small batch readymade disrupt coloring book.",
      "lastChanged": "2017-07-03T09:26:20.450681Z",
      "revision": 2
    },
    {
      "displayName": "Test name 1",
      "helpText": "Wayfarers sartorial authentic, small batch readymade disrupt coloring book.",
      "identifier": "29c968dd-8b83-4374-962d-32b9ef527e1b",
      "backgroundColour": "#9f0500",
      "foregroundColour": "#FFFFFF",
      "comment": "Wayfarers sartorial authentic, small batch readymade disrupt coloring book.",
      "description": "Wayfarers sartorial authentic, small batch readymade disrupt coloring book.",
      "lastChanged": "2017-07-03T09:25:52.955293Z",
      "revision": 2
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)
  • 我可以看到序列化器 .is_valid() 对于 PolicySerializer 来说是 True
  • 当我查看 valid_data 时,这三个字段丢失了(其余字段都在那里)
  • 我尝试过注释掉,read_only_fields但这似乎没有任何区别
  • 我在这里参考了 DRF 文档

我的问题:如何获取嵌套表示的 valid_data 中的标识符字段?

Ant*_*ash 5

默认情况下,在模型上editable设置为的字段在序列化器上。[ http://www.django-rest-framework.org/api-guide/serializers/#specifying-read-only-fields]Falseread_only

您应该使用不同的序列化程序进行创建,其中将显式给出字段,如下所示:

class ClassificationLabelDetailSerializer(serializers.ModelSerializer):
    identifier = serializers.CharField()

    class Meta:
        model = ClassificationLabel
        fields = ('displayName', 'helpText', 'backgroundColour', 'foregroundColour', 'comment', 'description', 'lastChanged', 'revision')
Run Code Online (Sandbox Code Playgroud)