Search code examples
djangopython-3.xdjango-modelsdjango-rest-frameworkdjango-mptt

Django Rest Framework list_route and queryset on tree structure


Trying to display hierarchy of categories through DRF serializer and it fails

GET /api/mobile/v1/categories/tree/ HTTP/1.1
Host: localhost:8000
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: c6b6c0e4-18f3-f8c4-1d77-75fc21a6a431

builtins.AttributeError

AttributeError: Got AttributeError when attempting to get a value for field `id` on serializer `CategoryTreeSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `TreeQuerySet` instance. Original exception text was: 'TreeQuerySet' object has no attribute 'id'.

Viewset

class CategoryViewSet(
        mixins.ListModelMixin,
        viewsets.GenericViewSet
):
    """Category view set.

    List model viewset for ``Category`` model.

    """
    queryset = Category.objects.all()
    serializer_class = CategorySerializer
    pagination_class = None

    @decorators.list_route(methods=['get'])
    def tree(self, *args, **kwargs):

        categories = Category.objects.filter(parent=None).all()
        serializer = CategoryTreeSerializer(categories)
        return Response(status=status.HTTP_200_OK, data=serializer.data

My Model

class Category(MPTTModel):

    id = models.CharField(
        max_length=32,
        primary_key=True,
        unique=True,
        verbose_name=_('ID'),
        help_text=_('Forsquare ID of the category.'),
    )
    parent = TreeForeignKey(
        'self',
        blank=True,
        null=True,
        related_name='children',
        db_index=True,
        verbose_name=_('Parent category'),
        help_text=_('Parent category.'),
    )
    name = models.CharField(max_length=255, verbose_name=_('Name'))
    plural_name = models.CharField(
        max_length=255,
        verbose_name=_('Plural name')
    )

    class Meta:
        verbose_name = _('Category')
        verbose_name_plural = _('Categories')

    class MPTTMeta:
        order_insertion_by = ['name']

    def __str__(self):
        return self.name

Serializer

class CategoryTreeSerializer(serializers.ModelSerializer):
    """Category serializer.

    Serializer for ``Category`` model. Excludes fields specified for MPTT.

    """
    children = serializers.ListField(child=RecursiveField())

    class Meta:
        model = Category
        fields = ('id', 'name', 'plural_name', 'children',)

Solution

  • ok worked after the following changes

    class CategoryViewSet(
            mixins.ListModelMixin,
            UserFavoritesMixin,
            viewsets.GenericViewSet
    ):
        """Category view set.
    
        List model viewset for ``Category`` model.
    
        """
        queryset = Category.objects.all()
        serializer_class = CategorySerializer
        pagination_class = None
    
        @decorators.list_route(methods=['get'])
        def tree(self, *args, **kwargs):
            """
            """
            categories = Category.objects.filter(level=0).all()
            serializer = CategoryTreeSerializer(categories, many=True)
            return Response(status=status.HTTP_200_OK, data=serializer.data)
    
    
    class CategoryTreeSerializer(serializers.ModelSerializer):
        """Category serializer.
    
        Serializer for ``Category`` model. Excludes fields specified for MPTT.
    
        """
        children = RecursiveField(many=True)
    
        class Meta:
            model = Category
            fields = ('id', 'name', 'plural_name', 'children',)