2016-11-23 104 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