Skip to content
thesarfo

Note

Creating Serializers

Converting model instances into dictionaries with a Serializer class, handling missing objects, and serializing a whole queryset with many=True.

views 0
  • Now we have written our api views, but we want to return the actual products and product details in our database in the browser. So we need to find a way to convert those product objects into json objects so they can be returned in the browser.

  • Now, DRF has a class called “JSONRenderer” which has a method called “render(dict)”. The render returns a json object but it takes a dictionary as a parameter. meaning that if we’re able to convert our product objects into python dictionaries and pass them to this render method, they can be displayed in the browser.

  • This is where a Serializer comes in, a serializer in drf allows us to convert a model instance(product object) into a dictionary.

Creating a serializer

To create a serializer, you have to create a file called “serializers.py” and then specify the fields in your model that you want to serialize. see below

from rest_framework import serializers
class ProductSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(max_length=255)
unit_price = serializers.DecimalField(max_digits=6, decimal_places=2)

Creating a serializer class is just the same as creating a model class. Just that the Serializer class name has to identify the Model class youre trying to serialize. And the serializer class inherits from the serializers.Serializer.

Also in creating a serializer field, you use ‘serializer.’ as a prefix, unlike a model field where you use the ‘models.’ prefix.

  • Now that we have our serializer, we can use it to convert our product object into a python dictionary

Converting into python dictionary

  • To serialize our model and return it, we go back to our view.py file, and import both our product model and product serializer. and then in our view function we need to get the product with the id we want, serialize it and then include it in the response. See below
from django.shortcuts import render
from django.http import HttpResponse
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Product
from .serializers import ProductSerializer
@api_view()
def product_list(request):
return Response('ok')
@api_view()
def product_detail(request, id):
'''these are the only product detail we wanna return in the browser'''
product = Product.objects.get(pk=id) #getting the product with the id we want
serializer = ProductSerializer(product) #serializing the product object
return Response(serializer.data)

Note that the moment we create the serializer, the serializer automatically converts our objects into a python dictionary. And this dictionary is stored in “serializer.data”. So then we return the serializer.data in our response.

So in this implementation we dont use the Json renderer because all this things happen under the hood.

  • Now when you check the browser, you will see that the product detail will have been converted to string automatically by drf. we change this by going into our settings.py file and then adding this setting
REST_FRAMEWORK = {
'COERCE_DECIMAL_TO_STRING': False
}

Now what if we are trying to access a product that doesnt exist. for instance product with index 0. we get an exception in the browser. So to fix this, we can use a try except block to serialize the product if it exists if not we return a 404 not found error. see below

@api_view()
def product_detail(request, id):
try:
product = Product.objects.get(pk=id)
serializer = ProductSerializer(product)
return Response(serializer.data)
except Product.DoesNotExist:
return Response(status=404)

Using “status=404” is hardcoding, and its not really practical. so instead we import http status from drf and then we set the relevant status code. See thee below for the updated version

from rest_framework import status
@api_view()
def product_detail(request, id):
try:
product = Product.objects.get(pk=id)
serializer = ProductSerializer(product)
return Response(serializer.data)
except Product.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)

A much better way

Instead of even using the status you imported, you can use a django shortcut called “get_object_or_404”. It kind of does the try except functionality and tries to get the object and if it doesnt exist it returns a 404 status code. see below

This means we need to get rid of the try catch block and replace the “Product.objects.get(pk=id)” with the “get_object_or_404”. see below

from django.shortcuts import get_object_or_404
@api_view()
def product_detail(request, id):
product = get_object_or_404(Product, pk=id) #first arg is the model you're getting and second arg is what you're getting i.e the primary key. in this case it is the id
serializer = ProductSerializer(product)
return Response(serializer.data)

Returning all products

Now in our product list, we want to return everything. we go through the normal process of creating a serializer and then converting it into a dictionary. see below

@api_view()
def product_list(request):
queryset = Product.objects.all() # getting all products returns a queryset
serializer = ProductSerializer(queryset, many=True) # we serialize the queryset and many=True means it should iterate through all items in the queryset and then convert each one into a dictionary
return Response(serializer.data)