Создать вложенные объекты в Django Rest Framework - PullRequest
0 голосов
/ 20 января 2019

Я пытаюсь создать вложенные объекты в 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 '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' в виде массива объектов. Однако, когда я пытаюсь создать новый список с элементом, происходит сбой с этой ошибкой:

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

Я прочитал это сообщение : я вижу ту же ошибку, если использую API с возможностью просмотра, поэтому, похоже, другая проблема.

  1. Почему возникает ошибка? 'список' предоставляется в коде согласно примеру. Это UUID, это требует специальной обработки?

  2. Вторая проблема, которая затрудняет мне отладку ... почему операторы print в методе 'create' ничего не записывают в консоль? «hello one» появляется при запуске сервера, но «hello two» в консоли никогда не появляется.

Большое спасибо за любую помощь!

Обновление: с этого поста кажется, что создание вложенных объектов работает наоборот, как я и ожидал - ItemSerializer запускается до ListSerializer, даже если элемент не может существовать без списка. Удаление «списка» из полей ItemSerializer означает, что создание теперь успешно, ура! И мой текст отладки напечатан, показывая, что теперь вызывается метод создания ListSerializer.

Вот определение рабочих полей в ItemSerializer:

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

У меня также была опечатка в ListSerializer. return list должно быть return newlist.

1 Ответ

0 голосов
/ 21 января 2019

Проблема с вашим ItemSerializer, в полях он содержит поле list , и вы не передаете это значение, оно будет создано внутри метода create ListSerializer.поэтому во время проверки он проверяет значение, поэтому он возвращает ошибку проверки.

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