在Django Rest框架中创建嵌套对象 [英] Create nested objects in django rest framework

查看:104
本文介绍了在Django Rest框架中创建嵌套对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试根据文档

这是我的模型。

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:

Here's my 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

这是我的send的cURL ng数据:

And here's the cURL that I'm sending with the data:

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

据我所知,与文档中的示例匹配,我认为数据以项目作为对象数组的格式正确。但是,当我尝试使用项目创建新列表时,它失败并显示以下错误:

As far as I can see, this matches the example in the docs, and I think the data is correctly formatted with 'items' as an array of objects. However when I try to create a new list with an item, it fails with this error:

{"items":[{"list":["This field is required."]}]}

我阅读了此帖子:如果我使用可浏览的API,则会看到相同的错误,因此似乎

I read this post: I see the same error if I use the browsable API, so it seems a different problem.


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

  1. Why is there an error? 'list' is provided in the code as per the example. It's a UUID, does that need special handling?

第二个问题使我难以调试...为什么不使用print语句在创建方法中写入任何内容到控制台?服务器启动时出现 hello one,但控制台中从未出现 hello one。

A second issue that is making it harder for me to debug...why don't the print statements in the 'create' method write anything to the console? "hello one" appears when the server starts, but "hello two" never appears in the console.

非常感谢寻求帮助!

更新:从这篇文章看来,创建嵌套对象的工作方式与我预期的相反-ItemSerializer在ListSerializer之前运行,即使没有列表就不能存在项目。从ItemSerializer字段中删除列表意味着创建成功,哇!并且打印了我的调试文本,表明现在正在调用ListSerializer的create方法。

Update: from this post it seems that creating nested objects works the other way around to what I expected - ItemSerializer runs before ListSerializer, even though an item cannot exist without a list. Removing 'list' from the ItemSerializer fields means that the creation now succeeds, hurrah! And my debug text is printed, showing that ListSerializer's create method is now being called.

这是ItemSerializer中的工作字段定义:

Here's the working fields definition in ItemSerializer :

fields = ('id', 'title', 'description', 'slug', 'modified_at', 'order')

我在ListSerializer中也有错字。 返回列表应该是返回新列表

I also had a typo in ListSerializer. return list should be return newlist.

推荐答案

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

Issue is with your ItemSerializer, in fields it's containing the list field, and you are not passing that value, it will create inside create method of ListSerializer. so at validation time it check for value, that why it's return the validation error.

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

这篇关于在Django Rest框架中创建嵌套对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆