2015-02-09 55 views
3

我有一類代表一個工作,代表標籤,其描述了作業和一個類,那麼我在它們之間具有類製作的關係(結合表),所以作業可以由多個標籤來描述:如何用DRF中的一個請求創建多個對象(相關)?

class JobTag(models.Model): 
    job = models.ForeignKey(Job, unique=False, related_name='jobtags') 
    tag = models.ForeignKey(Tag, unique=False, related_name='Tag_For_Job') 

    created_time = models.DateTimeField(auto_now_add = True) 
    modified_time = models.DateTimeField(auto_now = True) 

    class Meta: 
     unique_together = ('job', 'tag',) 

    def __unicode__(self): 
     return 'Tag '+self.tag.name +' for job '+ self.job.name 

然後,我有串行:

class TagSerializer(serializers.HyperlinkedModelSerializer): 
    class Meta: 
     model = Tag 
     fields = ('url','name','badge_pic') 
     read_only_fields = ('name','badge_pic') 

class JobTagSerializer(serializers.HyperlinkedModelSerializer): 
    tag = TagSerializer() 
    class Meta: 
     model = JobTag 
     fields = ('tag',) 
     depth=1 

class JobSerializer(serializers.HyperlinkedModelSerializer): 
    jobtags=JobTagSerializer(many=True) 
    class Meta: 
     model = Job 
     fields = ('url','name', 'employer','jobtags','description') 
     read_only_fields = ('employer',) 

因此,對GET請求的HTTP響應:

{ 
     "url": "http://127.0.0.1:8000/api/jobs/2/", 
     "name": "Odprac mi sneh", 
     "employer": "http://127.0.0.1:8000/api/users/4/", 
     "jobtags": [ 
      { 
       "tag": { 
        "url": "http://127.0.0.1:8000/api/tags/2/", 
        "name": "Odhadzovanie snehu", 
        "badge_pic": "http://127.0.0.1:8000/media/pictures/tags/0005.jpg" 
       } 
      } 
     ], 
     "description": "blablabla" 
    } 

我的問題是預tty非常明顯,我如何創建一個工作實例,並用一個POST HTTP請求將它們與相關的JobTags持久存儲?

我試圖重複這個方法http://www.django-rest-framework.org/api-guide/serializers/#writable-nested-representations

class JobSerializer(serializers.HyperlinkedModelSerializer): 
     jobtags=JobTagSerializer(many=True) 
     class Meta: 
      model = Job 
      fields = ('url','name', 'employer','jobtags','description') 
      read_only_fields = ('employer',) 
     def create(self, validated_data): 
      jobtag_data = validated_data.pop('jobtags') 
      job = Job.objects.create(**validated_data) 
      JobTag.objects.create(job=job, **jobtag_data) 
      return job 

又恢復「創造(的)參數**後必須是一個映射,未列出」的錯誤,所以我應該request.data JSON樣子?

或者這種方法不能用於我的情況,我應該做一些完全不同的事情嗎?

我將不勝感激任何幫助。

編輯

,如果我嘗試訪問列表:

def create(self, validated_data): 
     jobtag_data = validated_data.pop('jobtags') 
     job = Job.objects.create(**validated_data) 
     JobTag.objects.create(job=job, **jobtag_data[0]) 
     return job 

我創另一個錯誤: 「不能分配 」OrderedDict()「: 」JobTag.tag「 必須是一個」 標籤「例子」。 所以即時猜測我發佈的json格式錯誤?我試圖topost數據是這樣的:

{ 
     "name": "Odprac mi sneh", 
     "jobtags": [ 
      { 
       "tag": { 
        "url": "http://127.0.0.1:8000/api/tags/2/" 
       } 
      } 
     ], 
     "description": "veela sneu nemam ruky makam makam makamam",   
    } 
+0

您是否可以不遍歷'jobtag_data'併爲每個項目創建一個'JobTag'實例? – Fiver 2015-02-09 22:43:25

+0

它看起來像驗證數據中的工作標籤由一些OrdedDict代表,這是不可接受的,我編輯了問題 – 2015-02-09 22:53:45

回答

2

如果有其他人正面臨這種情況,我想出了最合適的解決方案,以便hyperl jobtags的着墨系列化創建時對象和嵌套序列被用作輸出,使用的是:

我寫串行每個這些情況中,用於發送到客戶端的數據的序列化:

class JobTagNestedSerializer(serializers.HyperlinkedModelSerializer): 
    tag = TagSerializer() 
    class Meta: 
     model = JobTag 
     fields = ('tag',) 
     depth=1 



class JobNestedSerializer(serializers.HyperlinkedModelSerializer): 
    jobtags=JobTagNestedSerializer(many=True,read_only=True) 
    class Meta: 
     model = Job 
     fields = ('url','name', 'employer','jobtags','description') 
     read_only_fields = ('employer',) 

和創建新的工作,所以從客戶端發送到DRF數據:

class JobTagSerializer(serializers.HyperlinkedModelSerializer): 
     class Meta: 
      model = JobTag 
      fields = ('tag',) 

class JobCreateSerializer(serializers.HyperlinkedModelSerializer): 
     jobtags=JobTagSerializer(many=True,required=False) 
     class Meta: 
      model = Job 
      fields = ('url','name', 'employer','jobtags','description') 
      read_only_fields = ('employer',) 

     def create(self, validated_data): 
      tag_data = validated_data.pop('jobtags') 
      job = Job.objects.create(**validated_data) 
      for tag in tag_data: 
       d=dict(tag) 
       JobTag.objects.create(job=job, tag_id=d['tag'].pk) 
      return job 

所以DRF期待從客戶端POST JSON來的樣子:

{ 
     "name": "Odprac mi sneh", 
     "employer": "http://127.0.0.1:8000/api/users/4/", 
     "jobtags": [ 
      { 
       "tag": "http://127.0.0.1:8000/api/tags/2/" 
      }, 
      { 
       "tag": "http://127.0.0.1:8000/api/tags/5/" 
      } 
     ], 
     "description": "veela sneu nemam ruky makam makam makamam" 
    } 
+0

這不起作用。與modelSerializer – Aryan 2016-11-03 11:08:59

+0

是的,例如「http://127.0.0.1:8000/api/tags/2/」是相關資源的uri(超鏈接),因此使用HyperlinkedModelSerializer即可。如果你打算使用modelSerializer,你應該使用另一個相關資源的唯一標識符,如主鍵(我想)。 – 2016-11-03 12:11:54

1

我相信你應該提供id,而不是每個標籤在你的POST數據url,像這樣:

{ 
    "name": "Odprac mi sneh", 
    "tags": [ 
     { 
      "id": 2 
     }, 
     { 
      "id": 3 
     } 
    ], 
    "description": "veela sneu nemam ruky makam makam makamam" 
} 

然後,在你create方法你應該能夠迭代標籤:

def create(self, validated_data): 
    tag_data = validated_data.pop('tags') 
    job = Job.objects.create(**validated_data) 

    for tag in tag_data: 
     JobTag.objects.create(job=job, tag_id=tag["id"]) 

    return job 
+0

這樣,序列化數據的驗證不理解你的「標籤」字段,我想這可以工作,如果我重寫我的串行器從超鏈接序列化到模型串行器,因此foreignkey關係由PrimaryKey表示,而不是url。但我仍然寧願保留超鏈接的序列。無論如何,非常感謝您的幫助,我真的很感激。 – 2015-02-10 16:08:47

+0

沒問題,很高興你把它整理出來。 – Fiver 2015-02-10 16:19:17

相關問題