django rest framework - как остановить повторение детей на уровне root - PullRequest
1 голос
/ 30 апреля 2020

я работаю с вложенными самореферентными объектами django, и у меня есть следующая Category модель

class CategoryManager(models.Manager):
    def all(self):
        qs = super(CategoryManager, self).filter(parent=None)
        return qs

class Category(models.Model):
    name = models.CharField(max_length=250)
    slug = models.SlugField(max_length=255, unique=True)
    description = models.TextField(blank=True)
    # description_json = JSONField(blank=True, default=dict)
    parent = models.ForeignKey(
        "self", null=True, blank=True, related_name="sub_category", on_delete=models.CASCADE
    )
    background_image = models.ImageField(
        upload_to="category-backgrounds", blank=True, null=True
    )

    objects = CategoryManager

для рекурсивного представления, я применил следующие сериализаторы

class RecursiveSerializer(serializers.Serializer):
    def to_representation(self, value):
        serializer = self.parent.parent.__class__(value, context=self.context)
        return serializer.data

class CategoryListSerializer(ModelSerializer): 
    sub_category = RecursiveSerializer(many=True, read_only=True)

    class Meta:
        model = Category
        fields = (
            # 'url',
            'name',
            'slug',
            'description',
            'parent',
            'background_image',
            'sub_category'
        )

и view,

class CategoryListAPIView(ListAPIView):
    queryset = Category.objects.all()
    serializer_class = CategoryListSerializer

создает следующий результат.

[
    {
        "name": "Food",
        "slug": "food",
        "description": "",
        "parent": null,
        "background_image": null,
        "background_image_alt": "",
        "sub_category": [
            {
                "name": "Rice",
                "slug": "rice",
                "description": "",
                "parent": 20,
                "background_image": null,
                "background_image_alt": "",
                "sub_category": []
            }
        ]
    },
    {
        "name": "Rice",
        "slug": "rice",
        "description": "",
        "parent": 20,
        "background_image": null,
        "background_image_alt": "",
        "sub_category": []
    }
]

Здесь у родительской категории Food есть дочерняя категория Rice, что хорошо, но проблема в том, что ребенок категория Rice повторяется на уровне root, как я могу это остановить.

1 Ответ

0 голосов
/ 01 мая 2020

Попробуйте добавить parent=None к вашему набору запросов на уровне ViewSet.

class CategoryListAPIView(ListAPIView):
    queryset = Category.objects.filter(parent=None)
    serializer_class = CategoryListSerializer

Довольно умное решение с рекурсивными сериализаторами! Единственная проблема в том, что он будет генерировать лотов запросов. В зависимости от вашей базы данных вам, вероятно, будет лучше:

  1. Использование рекурсивного CTE ( очень хороший блог , возвращающий json непосредственно из postgres)
  2. Запросите все записи сразу (если это небольшая таблица), создайте дерево в python и верните ответ напрямую. Кэшируйте ответ и сделайте недействительной запись кэша, когда произойдет обновление / вставка.

Примечание:

Нет действительно веской причины использовать ListApiView, если вы не ' • Поддержка подробных видов (/view/:pk/) и фильтрация / разбиение на страницы / сортировка. В этом случае вы можете просто использовать APIView с методом get().

...