Serialization in Django

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/'

Create Request
get request
Get Request
get detailed request
Get Detailed Request
Update Request
Update Request
Update Request
Update Request

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.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *