我正在尝试根据docs在Django Rest Framework中创建嵌套对象。
这是我的模型。py:
import uuid
from django.db import models
from django.utils.http import int_to_base36
from django.core.validators import MaxValueValidator, MinValueValidator
from django.contrib.auth import get_user_model
ID_LENGTH = 12
USER = get_user_model()
def slug_gen():
"""Generates a probably unique string that can be used as a slug when routing
Starts with a uuid, encodes it to base 36 and shortens it
"""
#from base64 import b32encode
#from hashlib import sha1
#from random import random
slug = int_to_base36(uuid.uuid4().int)[:ID_LENGTH]
return slug
class List(models.Model):
"""Models for lists
"""
slug = models.CharField(max_length=ID_LENGTH, default=slug_gen, editable=False)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created_by = models.ForeignKey(USER, on_delete=models.CASCADE, related_name='list_created_by')
created_at = models.DateTimeField(auto_now_add=True)
modified_by = models.ForeignKey(USER, on_delete=models.SET_NULL, null=True,
related_name='list_modified_by')
modified_at = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=255)
description = models.CharField(max_length=255, blank=True, default='')
is_public = models.BooleanField(default=False)
def __str__(self):
return self.title
class Item(models.Model):
"""Models for list items
"""
slug = models.CharField(max_length=ID_LENGTH, default=slug_gen, editable=False)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
modified_at = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=255)
description = models.CharField(max_length=255, blank=True, default='')
list = models.ForeignKey(List, on_delete=models.CASCADE, related_name='items')
order = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(10)])
class Meta:
unique_together = ('list', 'order')
ordering = ['order']
def __unicode__(self):
return '%d: %s' % (self.order, self.title)
这是我的serializers.py:
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('id', 'title', 'description', 'slug', 'modified_at', 'list', 'order')
class ListSerializer(serializers.ModelSerializer):
items = ItemSerializer(many=True)
print('hello one')
# automatically set created_by as the current user
created_by = serializers.PrimaryKeyRelatedField(
read_only=True,
default=serializers.CurrentUserDefault()
)
class Meta:
model = List
fields = ('id', 'title', 'description', 'is_public',
'slug', 'created_by', 'created_at',
'modified_by', 'modified_at', 'items')
def create(self, validated_data):
print('hello two')
items_data = validated_data.pop('items', None)
print(validated_data)
print(items_data)
newlist = List.objects.create(**validated_data)
for item_data in items_data:
Item.objects.create(list=newlist, **item_data)
return list
这是我随数据发送的cURL:
curl 'http://localhost:3000/api/v1/content/lists/' -H 'Authorization: Token ae367b73efbb7d6849af421d553e9c243b4baf7b' -H 'Origin: http://localhost:3000' -H 'Accept-Encoding: gzip, deflate, br' -H 'dataType: json' -H 'Accept-Language: en-GB,en-US;q=0.9,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' -H 'Content-Type: application/json' -H 'Accept: */*' -H 'Referer: http://localhost:3000/newlist' -H 'Connection: keep-alive' --data-binary '{"title":"Hats","description":"","items":[{"title":"Fedora","order":1}]}' --compressed
据我所知,这与文档中的示例匹配,并且我认为数据已正确地以“项目”作为对象数组的格式。但是,当我尝试使用项目创建新列表时,它失败并显示以下错误:
{"items":[{"list":["This field is required."]}]}
我读了this post:如果使用可浏览的API,我会看到相同的错误,因此这似乎是一个不同的问题。
为什么会出现错误?根据示例,在代码中提供了“列表”。这是一个UUID,需要特殊处理吗?
第二个问题使我难以调试...为什么'create'方法中的print语句不向控制台写入任何内容?服务器启动时会出现“ hello one”,但控制台中永远不会出现“ hello two”。
非常感谢您的帮助!
更新:从this post起,似乎创建嵌套对象的工作方式与我预期的相反:ItemSerializer在ListSerializer之前运行,即使没有列表就无法存在项目。从ItemSerializer字段中删除“列表”意味着创建成功了,哇!并且我的调试文本已打印出来,表明现在正在调用ListSerializer的create方法。
这是ItemSerializer中的工作字段定义:
fields = ('id', 'title', 'description', 'slug', 'modified_at', 'order')
我在ListSerializer中也有错字。 return list
应该是return newlist
。
答案 0 :(得分:1)
问题与您的ItemSerializer一起使用,在包含 list 字段的字段中,并且您没有传递该值,它将在ListSerializer的create方法中创建。因此,在验证时,它会检查值,这就是为什么它会返回验证错误。
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('id', 'title', 'description', 'slug', 'modified_at', 'order')