Search code examples
djangodjango-rest-frameworkdjango-serializer

how to pass a QuerySet instance to serializer?


I'm using raw sql (using orm is working) for fetching products and i'm getting this error

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

This is the get function:

def get(self, request, store_id, format=None):
    with connection.cursor() as cursor:
        user = request.user
        check_auth = get_object_or_404(
            Store, id=store_id, owner_id=user.id)
        if check_auth != None:
            connection.cursor()
            cursor.execute('SELECT * FROM products')
            products = cursor.fetchall()
            serializer = ProductSerializer(products, many=True)
            return Response(serializer.data)
    raise Http404

and here's the serializer class:

class ProductSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(read_only=True)
category = CategorySerializer()

class Meta:
    model = Product
    fields = ['id', 'store_id', 'name', 'summary',
              'description', 'category', 'main_image', 'price', 'offer_price', 'cost', 
    'available_quantity']

Solution

  • Django ModelSerializer will work only in the case of QuerySet object retrieved from models. Executing queries using a connection object will give result in Python native data types like List and Tuple for which ModelSerializer will not work. So, in this case, cursor.fetchall() will give the list of tuples, and each tuple consists of a relational DB row. So to serialize these data types instead of ModelSerializer use just Serializer. Below code snippet will give the detail idea on SerializerMethodField.

    View.py

    class RawQueryDjango(APIView):
        def get(self, request):
            from django.db import connection
            cursor = connection.cursor()
            cursor.execute('select * from products_usermodel')
            res = cursor.fetchall()
            serializer = RawQuerySerializer(res, many=True)
            print(serializer.data)
            return Response({'detail': serializer.data})
    

    Serializer.py

    from rest_framework.serializers import Serializer, ModelSerializer, SerializerMethodField
    
    
    class RawQuerySerializer(Serializer):
        name = SerializerMethodField()
        last_name = SerializerMethodField()
    
        def get_name(self, obj):
            return obj[1]
    
        def get_last_name(self, obj):
            return obj[2]    # index value at which last_name in tuple
    
    

    This will give the following response. In raw query execution no interaction with model has been done.

    {
        "detail": [
            {
                "name": "abc",
                "last_name": "sadfasd"
            },
            {
                "name": "asasasd",
                "last_name": "werwe"
            },
            {
                "name": "asdafa",
                "last_name": "1231weasd"
            },
            {
                "name": "sh",
                "last_name": "patil"
            }
        ]
    }