2016-11-23 224 views
1

這是我第一次使用DRF。無法與DRF創建()嵌套關係

我的模型:

class ServiceCategory(models.Model): 
    category = models.CharField(max_length=24) 

class Service(models.Model): 
    service = models.CharField(max_length=24) 
    category = models.ForeignKey('ServiceCategory') 

他們的串行:

class ServiceCategorySerializer(serializers.ModelSerializer): 
    class Meta: 
     model = ServiceCategory 
     fields = ('id', 'category') 

class ServiceSerializer(serializers.ModelSerializer): 
    category = ServiceCategorySerializer() 

    class Meta: 
     model = Service 
     fields = ('service', 'category') 

    def create(self, data): 
     return Service.objects.create(**data) 

和視圖:

elif request.method == 'POST': 
    serializer = ServiceSerializer(data=request.data) 

    print(serializer.initial_data) # To debug the contents of the request 

    if serializer.is_valid(): 
     serializer.save() 
     return Response(serializer.data, status=status.HTTP_201_CREATED) 
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 

開始之前,我添加了嵌套類的ServiceSerializer,我沒有創建新服務的問題。​​輸出<QueryDict: {'category': ['1'], 'service': ['EC2']}>顯然我提供的類別請求,但我得到"category" : ["This field is required"]錯誤。

所以我認爲這個問題可能與我在ServiceSerializer中的create(self, data)方法有關,但我無法指出它究竟有什麼問題。

我錯過了什麼?

UPDATE

沒有ServiceCategorySerializer在ServiceSerializer,並且此視圖:

elif request.method == 'POST': 
    serializer = ServiceSerializer(data=request.data) 

    print(serializer.initial_data) # for debugging 

    if serializer.is_valid(): 
     print(serializer.data) # for debugging 

serializer.initial_data回報<QueryDict: {'category': ['1'], 'service': ['EC2']}>serializer.data返回{'service': 'EC2', 'category': 1}所以我假設的serializer.data內容究竟會得到傳遞給ServiceSerializer的create()方法。本身,它的工作原理,但是當我包括ServiceCategorySerializer裏面,POST不通過,我得到同樣惱人的"category" : ["This field is required"]

我一直堅持這個超過6小時了。到底是怎麼回事???

回答

2

我有一個完整的工作的例子 - 你想達到什麼樣的 - 使用我在這個線程發現,只有信息:

型號:

from __future__ import unicode_literals 

from django.db import models 


class ServiceCategory(models.Model): 
    category = models.CharField(max_length=24) 


class Service(models.Model): 
    service = models.CharField(max_length=24) 
    category = models.ForeignKey('ServiceCategory') 

串行器:

from rest_framework import serializers 

from nestedd.models import ServiceCategory, Service 


class ServiceCategorySerializer(serializers.ModelSerializer): 
    class Meta: 
     model = ServiceCategory 
     fields = ('id', 'category') 


class ServiceSerializer(serializers.ModelSerializer): 
    category = ServiceCategorySerializer() 

    class Meta: 
     model = Service 
     fields = ('service', 'category') 

    def create(self, validated_data): 
     category_data = validated_data.pop('category') 
     # 'created' will be True if no existing category matches 
     category, created = ServiceCategory.objects.get_or_create(**category_data) 
     return Service.objects.create(category=category, **validated_data) 

瀏覽:

# Create your views here. 
from rest_framework import viewsets 

from nestedd.models import Service 
from nestedd.serializers import ServiceSerializer 


class ServiceViewSet(viewsets.ModelViewSet): 
    queryset = Service.objects.all() 
    serializer_class = ServiceSerializer 

網址:

from rest_framework.routers import DefaultRouter 

from nestedd.views import ServiceViewSet 

router = DefaultRouter() 
router.register(r'nested', ServiceViewSet, base_name='service') 

urlpatterns = router.urls 

應用網址:

url(r'^api/v2/', include('nestedd.urls')), 

這該怎麼我的郵遞員看喜歡:

Postman request

的問題 - POST數據格式

也許你犯了一個錯誤的POST查詢 - 如果你想使用嵌套的序列化,像這樣:

category = ServiceCategorySerializer() 

在其他一些串,你必須知道,第一個字段名稱被連接到母串行器,如:

{ 
    "service_name": "test", 
    "category": ... 
} 

什麼應該放在類別字段?好了 - 一個對象,因爲你告訴這個字段是另外一種串行,如果對象則:

{ 
    "service_name": "test", 
    "category": { 
     "category": "some_category" 
    } 
} 

和此對象指定這是由內部串行描述,所以基本上對模型的字段,當你通過只有「id」 - >很明顯,無法創建ServiceCategory,因爲ServiceCategory模型上的類別字段是必需的。

另一個注意:存在VS. NON EXISITNG類別

您在處理現有/不存在的類別時會遇到問題; 基本上你應該使ServiceCategory上的類別字段是唯一的,並在ServiceViewSet上發佈 - 檢查是否存在類別(如果是這樣,並將其分配給Service對象 - 如果不存在 - 創建類別) - 在這種情況下,您不需要通過類別ID每次。並在id時處理它 - 不存在。

+0

謝謝!滿分爲你 - 接受和upvoted。 – Duos

1

在發佈服務時,category字段必須包含PK,即整數。您的category字段serializer.initial_data包含一個帶有字符串的列表。

BTW1:您的service字段也有一個列表,當您的模型預期字符串(CharField)。這可能也是一個問題。

BTW2:無需在您的情況下覆蓋您的序列化程序的create

+0

是的。但'serializer.initial_data'和'serializer.validated_data'是不同的。例如,在另一個序列化器中,'serializer.initial_data'輸出''while'serializer。(''region','us-east-1'),('location','North Virginia')])' – Duos

+0

那麼,在第二個例子中,確實沒有' category',而你的模型聲明每個'Service'必須有一個類別(你的ForeignKey中沒有顯式的'null = True')。這就是爲什麼當調用'.is_valid()'時你的序列化器會報錯。 – lucasnadalutti

+0

我的不好。這是另一個序列化器,特別是RegionSerializer,它與ServiceSerializer完全沒有任何關係。我只是用它來指出,一般來說,'serializer.initial_data'包含列表,但'serializer.validated_data'不包含。 – Duos

1

正如the docs說,你應該實現在一個稍微不同的方式create()方法,先保存類別,如果不存在,然後將它傳遞給Service.objects.create()功能,像這樣的(未經測試):

def create(self, validated_data): 
    category_data = validated_data.pop('category') 
    # 'created' will be True if no existing category matches 
    category, created = ServiceCategory.objects.get_or_create(**category_data) 
    return Service.objects.create(category=category, **validated_data) 
+0

我實際上覆制粘貼這個,它不起作用。我嘗試了文檔推薦的所有內容,但都沒有成功。我傳遞的類別實際上是存在的,我希望在處理類別尚不存在的情況下通過它。 – Duos

+0

我更新了代碼。它是ServiceCategory,而不是Category。無論如何,請包括錯誤消息,而不是隻是說「它不工作」。 –

+0

哦,我已經相應地更改了代碼。並且錯誤信息仍然與我在我的問題中提到的一樣:'「category」:[「此字段是必需的]' – Duos