-
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 renderfrom django.http import HttpResponsefrom rest_framework.decorators import api_viewfrom rest_framework.response import Responsefrom .models import Productfrom .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)