在Django Rest框架中创建嵌套对象

时间:2019-01-20 18:08:17

标签: django django-rest-framework nested serializer

我正在尝试根据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,我会看到相同的错误,因此这似乎是一个不同的问题。

  1. 为什么会出现错误?根据示例,在代码中提供了“列表”。这是一个UUID,需要特殊处理吗?

  2. 第二个问题使我难以调试...为什么'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

1 个答案:

答案 0 :(得分:1)

问题与您的ItemSerializer一起使用,在包含 list 字段的字段中,并且您没有传递该值,它将在ListSerializer的create方法中创建。因此,在验证时,它会检查值,这就是为什么它会返回验证错误。

class ItemSerializer(serializers.ModelSerializer):
   class Meta:
      model = Item
      fields = ('id', 'title', 'description', 'slug', 'modified_at', 'order')