Search code examples
pythondjangodjango-rest-frameworkdjango-serializer

Django Rest Framework Serializer do not want to accept returned list, and returns AttributeError 'str' object has no attribute 'x'


So I'm trying to aggregate a list of colors and return the queryset to the serializer, the serialzier, however, does not seem to accept this for some reason.

When running the the commands in shell i get:

>>> from django.contrib.postgres.aggregates import ArrayAgg
>>> from inventory.models import Product
>>> products = Product.objects.filter(category__parent__name__iexact='fliser').distinct().aggregate(colors_field=ArrayAgg('colors__name'))
>>> print(products)
{'colors_field': ['Beige', 'Grå', 'Hvit', 'Sort', 'Beige', 'Gul', 'Rød']}

Which is the expected result.

The serializer is structured like this:

class ProductFiltersByCategorySerializer(serializers.ModelSerializer):
    """
    A serializer to display available filters for a product lust 
    """

    colors = serializers.StringRelatedField(read_only=True, many=True)

    class Meta:
        model = Product
        fields = ['colors']

The viewset looks like this:

class ProductFiltersByCategory(generics.ListAPIView):
    """
    This viewset takes the category parameter from the url and returns related product filters
    """

    serializer_class = ProductFiltersByCategorySerializer

    def get_queryset(self):
        category = self.kwargs['category']
        queryset = Product.objects.filter(category__parent__name__iexact=category).distinct().aggregate(colors_field=ArrayAgg('colors__name'))
        return queryset

And the relevant part of the model looks like this:

class Product(models.Model):

    ...
    colors = models.ManyToManyField(
        ProductColor,
        related_name='product_color'
    )
    ...

The error when trying to access the endpoint is 'str' object has no attribute 'colors'.

Wished output:

[
    {
        "colors": [
            "Red",
            "Orange",
        ],
    },
]

Solution

  • You don't need a ListAPIView class here, Use APIView as

    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    
    class MyAPIView(APIView):
        def get(self, request, *args, **kwargs):
            category = kwargs['category']
            agg_result = Product.objects.filter(
                category__parent__name__iexact=category
            ).distinct().aggregate(colors_field=ArrayAgg('colors__name'))
            return Response(agg_result)