2017-07-03 53 views
2

我不明白爲什麼特定的字段被丟棄在validated_data中。在驗證過程中丟失字段 - 嵌套序列化程序create()

投遞輸入以創建()的新實例,下面的行:因爲所述標識符屬性不存在 thisLabel = ClassificationLabel.objects.get(identifier=label.identifier) 引發錯誤:

AttributeError at /api/v1/policies/ 

'collections.OrderedDict' object has no attribute 'identifier

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

serializers.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 

models.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) 

發送時通過POST以下它丟棄標識符,從validated_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 
    } 
    ] 
} 
  • 我可以看到,串行.is_valid()是真正的PolicySerializer
  • ,當我看着那些validated_data三個字段缺失(其餘均爲有)
  • 我試着註釋掉read_only_fields而且似乎沒有任何區別
  • 我一直在引用文檔DRF here
    • 我已經保證了客戶端的內容類型設置正確,因爲有here
    • 別人seem將有類似的問題類似的問題

我的問題:我如何獲取嵌套表示的validated_data中的標識符字段?

+0

那你的「當發送有效載荷」的意思?這是一個POST請求嗎? – zaidfazil

+0

如果這是一個POST請求,那麼你需要了解序列化程序將不接受定義爲只讀的字段。 – zaidfazil

+0

謝謝@FazilZaid - 它是一個POST請求。我會看看是否省略嵌套序列化程序中的read_only_fields更改任何內容 – AndrewO

回答

0

默認情況下,在模型上的editable設置爲False的字段默認爲串行器。 [http://www.django-rest-framework.org/api-guide/serializers/#specifying-read-only-fields]

您應該使用創造一個不同的串行其中場將給予明確的,像這樣:

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

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

,謝謝@antash--就是這樣。關於此的一些附加說明: 1.如果您刪除字段 的'editable = False'參數,則需要執行數據庫遷移2.具有'editable = False'的字段不需要包含在' read_only_fields' - 它們自動包含在內 – AndrewO

1

ClassificationLabelDetailSerializer您設置identifierread_only場,和文檔狀態:

只讀字段包含在API輸出,但在創建或不應該包括在輸入 更新操作

這意味着它們不會被傳遞到validated_data,因爲它們不應該用於寫入操作。

read_only字段中刪除identifier,它應該工作。如果您需要使用identifier作爲read_only的其他地方的序列化器,則應該爲嵌套標籤創建另一個序列化器。

相關問題