DRF: вложенные сериализаторы с глубиной> 1 - PullRequest
0 голосов
/ 01 октября 2018

Я смотрю на "вложенные" сериализаторы, где есть вложенный сериализатор, вложенный в другой.Это кулинарная услуга, где рецепт имеет несколько направлений, каждое из которых имеет несколько ингредиентов.Я установил это с помощью внешних ключей.

Вот мои модели:

class Category(models.Model):
    """Model representing a recipe category"""
    name = models.CharField(max_length=200, help_text="Enter a recipe category (e.g Baking)")

    def __str__(self):
        """String for representing the Model object."""
        return self.name

class Ingredient(models.Model):
    """Model representing an ingredient in a direction"""
    name = models.CharField(max_length=250, help_text="The ingredient's name")
    quantity = models.CharField(max_length=200, help_text="How much of this ingredient.")
    direction = models.ForeignKey("Direction", help_text="This ingredient's direction", on_delete=models.CASCADE, related_name='ingredients')

    def __str__(self):
        """String for representing this recipe ingredient"""
        return f'{self.quantity} {self.ingredient}'

class Direction(models.Model):
    """Model representing a step in a recipe"""
    title=models.CharField(max_length=200)
    text=models.TextField(blank=True, help_text="Describe this step.")

    recipe=models.ForeignKey("Recipe", help_text="This direction's recipe", on_delete=models.CASCADE, related_name='directions')


    def __str__(self):
        """String for representing the Direction"""
        return self.title

class Recipe(models.Model):
    """Model representing a recipe."""
    title = models.CharField(max_length=200)

    notes = models.TextField(max_length=1000, help_text="Enter notes, reviews, ...")

    photos = models.ImageField(null=True, blank=True)

    category = models.ForeignKey(Category, help_text="This recipe's category", on_delete=models.CASCADE, related_name='recipes')

    def __str__(self):
        """String for representing the Model object."""
        return self.title

    def get_absolute_url(self):
        """Returns the url to access a detail record for this recipe."""

Я прочитал документы и подумал, что я мог бы просто использовать вложенный сериализатор в другом,Это вызвало у меня ошибку, указав, что «прямое назначение обратной стороне связанного набора запрещено».

Затем я заставил его работать с помощью этих сериализаторов:

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ('name',)

    def create(self, validated_data):
        category = Category.objects.create(**validated_data)
        return category


class IngredientSerializer(serializers.ModelSerializer):
    class Meta:
        model = Ingredient
        fields = ('quantity', 'name',)

    def create(self, validated_data):
        ingredient = Ingredient.objects.create(**validated_data)
        return ingredient

    def update(self, instance, validated_data):
        instance.quantity = validated_data.get('quantity', instance.quantity)
        instance.name = validated_data.get('name', instance.name)
        instance.direction = validated_data.get('direction', instance.direction)
        instance.save()
        return instance

class DirectionSerializer(serializers.ModelSerializer):
    ingredients = IngredientSerializer(many=True)

    class Meta:
        model = Direction
        fields = ('title', 'text', 'ingredients', )

    def create(self, validated_data):
        direction = Direction.objects.create(**validated_data)

        return direction

    def update(self, instance, validated_data):
        instance.title = validated_data.get('title', instance.title)
        instance.text = validated_data.get('text', instance.text)
        instance.recipe = validated_data.get('recipe', instance.recipe)

        instance.save()
        return instance


class RecipeSerializer(serializers.ModelSerializer):
    directions = DirectionSerializer(many=True)
    category = CategorySerializer()

    class Meta:
        model = Recipe
        fields = ('title', 'notes', 'photos', 'category', 'directions')

    def create(self, validated_data):
        directions_data = validated_data.pop('directions')
        category_data = validated_data.pop('category')
        category = Category.objects.create(**category_data)
        validated_data["category"] = category
        recipe = Recipe.objects.create(**validated_data)
        recipe.category = category
        for direction_data in directions_data:
            ingredients_data = direction_data.pop("ingredients")
            direction = Direction.objects.create(recipe=recipe, **direction_data)
            for ingredient_data in ingredients_data:
                Ingredient.objects.create(direction=direction, **ingredient_data)
        return recipe

    def update(self, instance, validated_data):
        instance.title = validated_data.get('title', instance.title)
        instance.notes = validated_data.get('notes', instance.notes)
        instance.photos = validated_data.get('photos', instance.photos)
        instance.category = validated_data.get('category', instance.category)

        instance.save()
        return instance

Я не уверенЧто из этого на самом деле необходимо в данный момент.По сути, я создаю вложенную структуру в функции create () рецепта.

Теперь к реальным вопросам: это похоже на хак.Является ли этот правильный и предполагаемый способ достижения нескольких вложенных сериализаторов?

Если я делаю это таким образом, мне даже нужны функции create () и update ()?

Большое спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...