A serialization class will convert a model into JSON data essential to saving data in an easily transferable format, for instance, saving data in a flash drive. In addition, serializers in the Django REST Framework are in charge of transforming objects into data types that JavaScript and front-end frameworks can understand.
After validating the incoming data, serializers also enable deserialization. As a result, it allows the parsed data to be transformed into complex types. The REST framework’s serializers are incredibly similar to Django’s Form and ModelForm classes. Further, ModelSerializer and HyperLinkedModelSerialzer are two of the most often used serializers.
This article covers everything on serializers. That is from the Django REST Framework to advanced serializer fields and arguments. This article assumes that you are OK with setting up both the Django project and the Django rest project. If not, checkout out our other tutorials that will help you do so.
Serializers: Creating and Using
Creating a simple Serializer
To make a basic serializer, import the rest_framework serializers class and define fields for a serializer. The latter is similar to a form or model in Django.
import serializer from rest_framework from rest_framework import serializers # creating a baic User Serializer class UserSerializer(serializers.Serializer): first_name = serializers.CharField(max_length = 200) last_name = serializers.CharField(max_length = 200) email = serializers.EmailField() gender = serializers.CharField(max_length = 200) date = serializers.DateTimeField()
It allows you to declare a serializer for any entity or object depending on the necessary fields. Serializers are used to both serialize and deserialize data.
How to serialize data using a Serializer
UserSerializer can now be used to serialize a user or a list of users. Using the Serializer class is similar to using the Form class. First, let’s create a User class to build a comment object that our serializer can understand.
import datetime object from datetime import datetime class User(object): def init(self, firstname,lastname,email, gender,date): self.first_name = firstname self.last_name =lastname self.email = email self.gender = gender self. date = created or datetime.now() # creating a user class
create a user object
this_user = User(first_name=’ann’,last_name=’brown’,email ='annbrown@example.com', gender ='female')
Next, you can attempt serializing this user object on the shell now that our object is ready. you can do so by executing the following command and running the code above
python manage.py shell
ModelSerializer
The ModelSerializer class is a shortcut that automatically creates a Serializer class with fields corresponding to the Model fields.
The ModelSerializer class is similar to a conventional Serializer class, with the following exceptions:
- Based on the model, it will automatically build a set of fields for you.
- Serializer’ Validators, such as unique together validators, will be generated automatically.
- It comes with basic.create() and.update() implementations.
class SerializerName(serializers.ModelSerializer): class Meta: model = ModelName fields = List of Fields
for example:
class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['id', 'first_name', 'last_name', 'email', 'gender', 'age', 'date']
According to the example above, all model fields on the class are mapped to appropriate serializer fields by default.
Choosing which fields to include
To indicate that all fields in the model are used, assign the fields attribute to the unique value all.
fields = '__all__'
The exclude attribute can specify a list of fields that should be ignored by the serializer, as shown below.
exclude = ['gender','age'] # 'id', 'first_name', 'last_name', 'email', 'gender', 'age', 'date' will be serialized
Further, you have the option of specifying read-only fields. Model fields and AutoField fields with editable=False will be set to read-only by default.
Here is an example of how to make the fields first_name and last_name to be read_only.
read_only_fields = ['first_name','last_name']
The extra_kwargs option also allows you to supply arbitrary additional keyword arguments on fields as a convenience. Below is an example of the same.
extra_kwargs = {'first_nname': {'read_only': True}}
Validation
With Django, validation is done in two places: on the form and the model instance. Validation is done exclusively on the serializer class in Django Rest Framework. When you use ModelSerializer, all of this is taken care of automatically.
If you want to use Serializer classes instead, you’ll have to explicitly declare the validation rules, as demonstrated in the subsequent sections.
class StudentReportRecord(models.Model): time_created = models.DateTimeField(default=timezone.now, editable=False) reference = models.CharField(unique=True, max_length=20) explanation = models.TextField() class StudentReportSerializer(serializers.ModelSerializer): class Meta: model = StudentReportRecord StudentReportSerializer(): id = IntegerField(label='ID', read_only=True) time_created = DateTimeField(read_only=True) reference = CharField(max_length=20, validators=[] ) explnation = CharField(style={'type': 'textarea'})
Validation at the Field Level
You can add validate_ methods to your Serializer subclass to specify specific field-level validation.
def validate_firstname(self, name_val): if 'ann' not in name_val.lower(): raise serializers.ValidationError("error message") return name_val
Object-Level Validation
Add a validate() function to your Serializer subclass to do any other validation that requires access to multiple fields.
def validateData(self, data): if data['begin'] > data['end']: raise serializers.ValidationError("wrong order, retry again.") return data
Overriding Serializer Methods
The create() and update() methods need implementation in our Serializer subclass to deliver complete object instances depending on the validated data.
def create(self, validated_data): return Student.objects.create(**validated_data) def update(self, instance, validated_data): instance.first_name= validated_data.get('first_name', instance.first_name ) instance.last_name= validated_data.get('last_name', instance.last_name ) instance.age = validated_data.get('age', instance.age) instance.save() return instance
How to include Extra context
When instantiating the serializer, you can specify a context argument to provide arbitrary additional context. The self.context attribute can retrieve the context dictionary from within any serializer field logic.
serializer = StudentSerializer(student, context={‘request’: request})
Nested relationships
Rather than the references to another item outlined above, the referred entity can be embedded. Or it is nested in the representation of the object that refers to it.
Serializers can be used as fields to express nested relationships. If the field is used to indicate a to-many relationship, the serializer field should have the many=True flag set.
from .models import Student, Registration from rest_framework import serializers class StudentSerializer(serializers.ModelSerializer): class Meta: model = Student fields = ['pk', 'first_name', 'last_name','age','gender'] class RegistrationSerializer(serializers.ModelSerializer): registration = RegistrationSerializer(many=True) class Meta: model = Registration fields = ['pk', 'name', 'registration']
SerializerMethodField
It is a read-only field. It obtains its value by invoking a method on the serializer class to which it is linked. It can be used to add any type of data to your object’s serialized representation.
from django.contrib.auth.models import User from django.utils.timezone import now from rest_framework import serializers class StudentSerializer(serializers.ModelSerializer): days_elapsed = serializers.SerializerMethodField() class Meta: model = Student def get_days_from_starting_day(self, obj): return (now() - obj.starting_date).days
Views
We’ll take advantage of Class-Based Views. The ViewSets work in the same way as Generic Views do. The only difference is that when you use ViewSet, you don’t have to develop two distinct views to get a list of items and a detail of a single object. We don’t use ViewSets to configure the URLs. Routers automatically build ViewSet URLs and bind methods for various request method types.
GenericViewSet
The GenericViewSet class includes the base set of generic view behavior, such as the get object and get queryset methods, but does not provide any actions/methods by default, such as GET, POST, or PUT.
ReadOnlyModelViewSet
A viewset with the default operations of list() and retrieve(). It only accepts requests with the GET method.
All the default actions in the ModelViewSet viewset include:
- Create()
- retrieve()
- update()
- partial_update()
- destroy()
- list()
In the file views.py, we would have the following lines of code to add ViewSet:
from rest_framework.viewsets import ReadOnlyModelViewSet from .serializers import StudentSerializer from .models import Student class StudentViewSet(ReadOnlyModelViewSet): serializer_class = StudentSerializer queryset = Student.objects.all()
You’ll need to override get_queryset() and get_serializer_class() methods or set queryset and serializer_class properties.
ReadOnlyModelViewSet was expanded to create StudentViewSet. Only get actions are available in our viewset.
ViewSet
Like regular actions, they can be used on a single item or an entire collection. Set the detail parameter to True or False to indicate this. The router will adjust its URL patterns as needed.
from rest_framework.viewsets import ReadOnlyModelViewSet from .serializers import StudentSerializer from .models import Student class StudentViewSet(ReadOnlyModelViewSet): serializer_class = StudentSerializer queryset = Student.objects.all() @action(detail=False) def get_student_list(self, request): pass @action(detail=True) def get_student(self, request, pk=None): pass @action(detail=True, methods=['post', 'delete']) def delete_student(self, request, pk=None): pass
HyperlinkedModelSerializer
The HyperlinkedModelSerializer class is identical to the ModelSerializer class, except instead of primary keys, it uses hyperlinks to express relationships. Instead of a primary key field, the serializer will contain a URL field by default.
A HyperlinkedIdentityField serializer field will be used to represent the URL field. On the other hand, a HyperlinkedRelatedField serializer field will describe any relationships on the model.
HyperlinkedModelSerializer syntax
class SerializerName(serializers.HyperlinkedModelSerializer): class Meta: model = ModelName fields = List of Fields
HyperlinkedModelSerializer example,
class UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User fields = ['id', 'first_name', 'last_name', 'email', 'gender', 'age', 'date']
Serializer Fields
Below, we look at some of the most frequently used serializer fields that you will find helpful in your day-to-day activities.
- BooleanField – is a boolean field used to wrap True or False values.
- NullBooleanField- is a boolean field that accepts True, False and Null values.
- CharField – CharField is used to store text representation.
- EmailField – EmailField is also a text representation, and it validates the text to be a valid e-mail address.
- RegexField – As the name defines, RegexField matches the string to a particular regex, else it raises an error.
- DecimalField – The DecimalField class is a decimal field that checks input against Python’s decimal instance.
- DateTimeField – DateTimeField is a serializer field that represents date and time.
- DateField – The DateField serializer field is used to represent dates.
- TimeField – The serializer field timefield is used to indicate time.
- DurationField – DurationField is a serializer field that represents time in seconds.
- ChoiceField – ChoiceField is a CharField that checks the input against a value from a limited number of options.
- URLField – URLField is a RegexField that validates the input against a URL matching pattern.
- SlugField – SlugField is a RegexField that validates the input against the pattern [a-zA-Z0-9_-]+.
- MultipleChoiceField – A MultipleChoiceField is a CharField that checks the input against a set of zero, one, or many values from a limited set of options.
- FileField – A FileField is a representation of a file. It validates FileFields as per Django’s standard.
- ImageField – ImageField is a representation of an image. In addition, it verifies that the content of the uploaded file matches a specified image format.
- ListField – ListField is a type of list field that checks input against a list of objects.
- JSONField – JSONField is a field class that verifies that the incoming data structure contains JSON primitives that are valid.
- IPAddressField – IPAddressField is a field that ensures the input is a valid IPv4 or IPv6 string.
- IntegerField – IntegerField is an integer field that validates the input against Python’s int instance.
- FloatField – FloatField is a float field that validates the input against Python’s float instance.
- HiddenField – HiddenField is a field type that doesn’t take its value from user input but rather from a default value or callable.
- DictField – DictField is a dictionary field that compares the input to a list of objects in a dictionary.
Serializer fields’ core arguments
Serializer fields are similar to Django Form fields and Django Model fields in that they require specific arguments to change their behavior. These will comprise but are not limited to the following list of arguments.
read only
The read-only argument is set to True to ensure that the field is used while serializing a representation but not when deserializing, creating, or modifying an instance.
allow_null
If None is supplied to a serializer field, an error is usually raised. If None should be regarded as a legitimate value, then set this keyword argument to True.
write only
Set this value to True to allow the field to be used while updating or creating an instance but not when serializing the representation.
error messages
It is a list of error codes that correspond to error messages.
Required
When serializing the instance, setting this to False also allows the object attribute or dictionary key to be removed from the output.
default
If this is selected, the default value for the field will be applied if no input value is provided.
Validators
Validators are a collection of validator functions that should be applied to the incoming field input. It usually returns or raises a validation error.
help text
It is a text string used in HTML form fields or other descriptive elements as a field description.
Initial
It is a value that should be used to pre-populate HTML form fields’ values.
Label
A label is a short text string used in HTML form fields or other descriptive elements as the field name.
Source
The field’s name is the name of the attribute that will be used to populate it.
Complete Implementation of CRUD using Serialization
Here is a complete to implement serialization on CRUD. In the end, you will find screenshots of the expected results if you can go through them successfully.
# models.py from django.db import models from model_utils import Choices # Create your models here. class Student(models.Model): STATUS = Choices('Active', 'Inactive') first_name = models.CharField(max_length=200) last_name = models.CharField(max_length=200) gender = models.CharField(max_length=200) age = models.CharField(max_length=20) status = models.CharField(max_length=20, choices=STATUS,default='Active') class Meta: app_label = 'student' def __str__(self): return self.title
# student/urls.py from django.urls import path from . import views urlpatterns = [ path('student-list/', views.studentList, name="student-list"), path('student-detail/<str:pk>/', views.studentDetail, name="student-detail"), path('student-create/', views.studentCreate, name="student-create"), path('student-update/<str:pk>/', views.studentUpdate, name="student-update"), path('student-delete/<str:pk>/', views.studentDelete, name="student-delete"), ]
#studentmanagement/settings.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('student.urls')), ]
# student/views.py from django.shortcuts import render from django.http import JsonResponse from rest_framework.decorators import api_view from rest_framework.response import Response from .serializers import StudentSerializer from .models import Student # Create your views here. @api_view(['GET']) def studentList(request): tasks = Student.objects.all().order_by('-id') serializer = StudentSerializer(tasks, many=True) return Response(serializer.data) @api_view(['GET']) def studentDetail(request, pk): tasks = Student.objects.get(id=pk) serializer = StudentSerializer(tasks, many=False) return Response(serializer.data) @api_view(['POST']) def studentCreate(request): serializer = StudentSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) @api_view(['POST']) def studentUpdate(request, pk): task = Student.objects.get(id=pk) serializer = StudentSerializer(instance=task, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) @api_view(['DELETE']) def studentDelete(request, pk): task = Student.objects.get(id=pk) task.delete() return Response('Item succsesfully delete!')
# student/serializers.py from rest_framework import serializers from .models import Student class StudentSerializer(serializers.ModelSerializer): class Meta: model = Student fields ='__all__'
# settings.py import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '3r8)6g*hni0mzm1$659da5-y6!rp75_odz%)3k@*c2n5rz$nv8' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ # 'student.apps.StudentConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'student', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'studentmanagement.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'studentmanagement.wsgi.application' # Database # https://docs.djangoproject.com/en/2.2/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # Password validation # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/2.2/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.2/howto/static-files/ STATIC_URL = '/static/'
Conclusion
Complex data, such as querysets and model instances, can be translated to native Python datatypes and then rendered into JSON, XML, or other content types using serializers. After validating the incoming data, serializers also enable deserialization.
As a result, it allows the parsed data to be transformed into complicated kinds.
Serializers in the REST framework works the same way as Django’s Form and ModelForm classes. It comes with a Serializer class that allows you a powerful, generic way to control the output of your responses and a ModelSerializer class that gives you a quick way to create serializers for model instances and querysets.
In addition, when the HTML format is requested, the Django REST Framework may generate human-friendly HTML output for each resource. These pages include forms for sending data to the resources using POST, PUT, and DELETE and forms for exploring resources.