Получение сериализованного прародителя из DRF отношения ManyToMany

#django #django-rest-framework

#django #django-rest-framework

Вопрос:

Я изо всех сил пытаюсь сериализовать прародителя (-ов) отношения ManyToMany в моих моделях. В сериализаторе продукта я хочу перечислить верхний уровень, Category основанный на SubCategory выбранном на Product . Мой код структурирован следующим образом:

models.py

 class Category(models.Model):
    
    ...
    name = models.CharField(
        _('category name'), 
        max_length=255, 
        unique=False
    )
    ...

class SubCategory(models.Model):
    parent = models.ForeignKey(
        Category, 
        on_delete=models.CASCADE, 
        related_name='children', 
    )
    name = models.CharField(
        _('category name'), 
        max_length=255, 
        unique=False
    )
    ...

class Product(models.Model):

    name = models.CharField(
        _('product name'),
        max_length=255,
        unique=True
    )
    category = models.ManyToManyField(
        SubCategory,
        related_name='products'
    )
    ...
  

serializers.py

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


class ProductsSerializer(serializers.ModelSerializer):

    ...
    category = serializers.StringRelatedField(read_only=True, many=True)
    parent_category = CategorySerializer(read_only=True, source='category.parent', many=True)
    ...

    class Meta:
        model = Product
        fields = (
            ...
            'parent_category',
            'category',
            ...
        )
  

В настоящее время поле parent_category не отображается в json-ответе.

Редактировать: serializers.py:

 class ProductCategorySerializer(serializers.ModelSerializer):
    
    class Meta:
        model = Category
        fields = ['name']

class ProductSubCategorySerializer(serializers.ModelSerializer):

    class Meta:
        model = SubCategory
        fields = ['name']

class ProductsSerializer(serializers.ModelSerializer):

    ...
    subcategory = ProductSubCategorySerializer(many=True, source='category')
    category = ProductCategorySerializer()
    ...

    class Meta:
        model = Product
        fields = (
            ...
            'category',
            'subcategory',
            ...
        )
  

Текущий вывод:

 [
    {
        "subcategory": [
            {
                "name": "sub category name",
                "category": {
                    "name": "main category name"
                }
            },
        ],
    }
]
  

желаемый результат:

 [
    {
        "category": [
            {
                "name": "main category name"
            },
            ...
        ],
        "subcategory": [
            {
                "name": "sub category name",
            },
            ...
        ],
    }
]
  

Комментарии:

1. Попробуйте сначала связать ProductsSerializer с SubCategory моделью, создающей serializer для нее — например. в ProductsSerializer , избавьтесь от parent_category и замените его на subcategory = SubCategorySerializer(many=True) — и как только вы это сделаете SubCategorySerializer , просто установите category = CategorySerializer() . Дайте мне знать, как это работает для вас.

2. Спасибо, что нашли время помочь! Я получаю Got AttributeError when attempting to get a value for field подкатегорию` в сериализаторе ProductsSerializer . Поле сериализатора может быть названо неправильно и не соответствовать какому-либо атрибуту или ключу в Product экземпляре. Исходный текст исключения был: объект ‘Product’ не имеет атрибута ‘subcategory’.`. Посмотрите на измененный код в редактировании сообщения на случай, если я вас неправильно понял.

3. Хм, ты можешь попробовать установить source="category" в ProductsSerializer s subcategory ? Если это тоже не сработает, просто используйте category вместо subcategory .

4. Установка источника сработала для подкатегорий, но поле категории, использующее ProductCategorySerializer() возвращает "category": { "name": null }, в ответе. Сообщение еще раз обновлено.

5. О, хорошо, теперь вам просто не хватает ссылки ProductSubCategorySerializer на ProductCategorySerializer , установив category = ProductCategorySerializer(source="parent") — кстати, вы установили это в ProductSubCategorySerializer . Не забудьте также добавить его в fields !

Ответ №1:

Полная serializers настройка должна быть такой:

 class ProductCategorySerializer(serializers.ModelSerializer):
    
    class Meta:
        model = Category
        fields = ['name']

class ProductSubCategorySerializer(serializers.ModelSerializer):
    category = ProductCategorySerializer(source="parent")

    class Meta:
        model = SubCategory
        fields = ['name', 'category']

class ProductsSerializer(serializers.ModelSerializer):

    ...
    subcategory = ProductSubCategorySerializer(many=True, source='category')
    ...

    class Meta:
        model = Product
        fields = (
            ...
            'subcategory',
            ...
        )
  

Комментарии:

1. Если вам нужно другое представление, дайте мне знать подробности.

2. Извините, я должен был прояснить это при публикации. Я обновил свой пост текущим и желаемым результатом.

3. Похоже, вы хотите отделить подкатегорию от категории, создавая массив для каждой; если вы не возражаете, если я спрошу, не создаст ли это некоторую путаницу? Например, вы не знаете, какая подкатегория принадлежит к какой категории.

4. Вы совершенно правы. Я перепроектировал в своей голове. Ваш ответ правильный и отмечен впоследствии.