这是我第一次使用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之前,我没有创建新服务的问题。 print(serializer.initial_data)
输出<QueryDict: {'category': ['1'], 'service': ['EC2']}>
显然我已经为请求提供了类别,但我收到"category" : ["This field is required"]
错误。
所以我认为问题可能出在ServiceSerializer中的create(self, data)
方法,但是我无法指出它究竟出了什么问题。
我错过了什么?
更新
ServiceSerializer中没有ServiceCategorySerializer,视图为:
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个多小时。发生了什么???
答案 0 :(得分: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
app urls:
url(r'^api/v2/', include('nestedd.urls')),
这就是我邮差的样子:
问题 - 发布数据格式
可能你做错了POST查询 - 如果你想使用嵌套的序列化器,就像这样:
category = ServiceCategorySerializer()
在其他一些序列化程序中,您必须知道第一个字段名称附加到父序列化程序,例如:
{
"service_name": "test",
"category": ...
}
应该在类别字段中放置什么?嗯 - 一个对象,因为你告诉这个字段是另一个序列化程序,如果是对象那么:
{
"service_name": "test",
"category": {
"category": "some_category"
}
}
在此对象中,您可以指定由内部序列化程序描述的模型的字段,因此基本上,当您仅传递“id” - &gt;时很明显,由于模型ServiceCategory上的类别字段是必需的,因此无法创建ServiceCategory。
另一个注意:EXISITING VS.没有明确的类别
处理现有/不存在的类别时会遇到问题; 基本上你应该在ServiceCategory上使类别字段唯一,并在ServiceViewSet上发布 - 检查类别是否存在(如果是,请将其分配给Service对象 - 如果不存在 - 创建一个类别) - 在这种情况下,您不需要传递类别每次都是id。当id - 不存在时处理它。
答案 1 :(得分:1)
在发布服务时,category
字段必须包含PK,即整数。 category
中的serializer.initial_data
字段包含带字符串的列表。
BTW1:当您的模型需要字符串(service
)时,您的CharField
字段也会有一个列表。这可能也是一个问题。
BTW2:在您的情况下无需覆盖序列化程序的create
。
答案 2 :(得分:1)
正如the docs中所述,您应该以稍微不同的方式实现create()
方法,如果类别尚未存在,则首先保存该类别,然后将其传递给{{ 1}}函数,像这样(未经测试的):
Service.objects.create()