# Topic covered
* Serialization
* Serializer
* ModelSerializer
* Regular Django views
* List View, Detail View
* Customize the serialization behavior
Serialization
Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes
that can then be easily rendered into JSON, XML or other content types.
Serializers also provide deserialization, allowing parsed data to be converted back into complex types,
after first validating the incoming data.
# Why Use Serializers?
Convert Django model objects → JSON (for APIs)
Convert JSON data → Django model objects (for saving to DB)
Validate incoming API data
Customize data representation
- Files
# Create
snippets/serializers.py
# Update
snippets/views.py
snippets/urls.py
3.1 Serializer
Gives you a powerful, generic way to control the output of your responses
# Create: serializer.py
class SnippetsSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(required=False, allow_blank=True, max_length=10)
# Add all the fieds that you want to Display/Serialize
...
def create(self, validated_data):
return Snippet.objects.create(**validated_data)
def update(self, instance, validated_data):
...
instance.title = validated_data.get('title', instance.title)
instance.save()
return instance
For GET request - adding only serializer fields is sufficient
For POST, PUT request - instance should be saved, So need to implement both .create() and .update() methods.
Serializer fields
Serializer fields handle converting between primitive values and internal datatypes.
They also deal with validating input values, as well as retrieving and
setting the values from their parent objects.
Field-level validation: https://www.django-rest-framework.org/api-guide/serializers/#field-level-validation
Object-level validation: https://www.django-rest-framework.org/api-guide/serializers/#object-level-validation
Serializing objects
https://github.com/amrit94/drf-guide/blob/01-Serializers/snippets/views.py
# 1. Translated the model instance into Python native datatypes
serializer = SnippetSerializer(Snippet.objects.all())
serializer.data
# Output: {'language': 'python', 'style': 'friendly'}
# 2. Then render the data into json
content = JSONRenderer().render(serializer.data)
content
# b'{"language":"python","style":"friendly"}'
Deserializing objects
https://github.com/amrit94/drf-guide/blob/01-Serializers/snippets/views.py
data = {"title": "Lang10", "language": "python", "style": "friendly"} """
serializer = SnippetSerializer(snippet, data=data)
serializer.is_valid()
serializer.validated_data
serializer.save()
3.2 ModelSerializer
It provides shortcut for creating serializers.
The ModelSerializer class is the same as a regular Serializer class, except that:
- It will
automatically generate a set of fieldsfor you, based on the model. - It will
automatically generate validatorsfor the serializer, such as unique_together validators. - It includes simple
default implementations of .create() and .update().
SnippetSerializer-class is replicating a lot of information that’s also contained in the Snippet-model. It would be nice if we could keep our code a bit more concise
ModelSerializer class
# SnippetSerializer-class --> ModelSerializer class
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
# Add only those fields which you want to display
fields = ['id', 'title', 'code', 'linenos', 'language', 'style']
To add all fields
fields = '__all__'
Additional keyword arguments
class CreateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['email', 'username', 'password']
read_only_fields = ['username']
extra_kwargs = {'password': {'write_only': True}}
3.3 Writing regular Django views using our Serializer
- This decorator marks a view as being
exempt from the protectionensured by the middleware - Normally
should not do this–> for POST, PUT and DELETE operations
3.3.1 List View
This view will list all the existing snippets, and also create a new snippet
# views.py
@csrf_exempt
def snippet_list(request):
if request.method == 'GET':
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return JsonResponse(serializer.data, safe=False)
# many=True - is used to serialize a queryset or list of objects
# instead of a single object instance
# By defaults `safe=True` --> to serialized Dict obj
# safe=False --> to serialized Non-Dict obj
# JsonResponse --> serialized to JSON
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = SnippetSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400)
# JSONParser().parse(request) - First parse a stream into Python native datatypes
# Then we restore those native datatypes into a fully populated object instance.
3.3.2 Detail View
This view handles individual snippet, and can be used to retrieve, update or delete the snippet.
@csrf_exempt
def snippet_detail(request, pk):
try:
snippet = Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist:
return JsonResponse({"error": "question not found "}, status=404)
if request.method == 'GET':
serializer = SnippetSerializer(snippet)
return JsonResponse(serializer.data)
# many=True not required - Coz of single instance of snippet
elif request.method == 'PUT':
data = JSONParser().parse(request)
serializer = SnippetSerializer(snippet, data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=200)
return JsonResponse(serializer.errors, status=400)
# SnippetSerializer(snippet, data=data) - snippet = old fields value
# data = updated fields value
elif request.method == 'DELETE':
snippet.delete()
return JsonResponse({"Success": "question deleted "}, status=204)
urls.py
urlpatterns = [
path('snippets/', views.snippet_list),
path('snippets/<int:pk>/', views.snippet_detail),
]
customize the serialization behavior
https://testdriven.io/blog/drf-serializers/
Two of the most useful functions inside the BaseSerializer class that we can override are to_representation() and to_internal_value().
By overriding them, we can change the serialization and deserialization behavior, respectively, to append additional data, extract data, and handle relationships.
- to_representation() allows us to change the serialization output
- to_internal_value() allows us to change the deserialization output
NOTE
- ‘rest_framework’, not added in installed app
- Works with POSTMAN
- Error in browser: rest_framework/api.html
- For this need to add