DEV Community

loading...
Cover image for Building a Powerful Serializer with The Django Python Web Framework

Building a Powerful Serializer with The Django Python Web Framework

courseprobe profile image Course Probe ・5 min read

Serialization transforms data into a format that can be stored or transmitted and then reconstructs it for use. DRF has the best-known serializers.

Serialization is the process of transforming data into a format that can be stored or transmitted and then reconstructing it. It’s used all the time when developing applications or storing data in databases, in memory, or converting it into files.

Suppose you’re creating software for an e-commerce site and you have an Order that registers the purchase of a single product, by someone, at a price, on a date:

**class Order:
    def __init__(self, product, customer, price, date):
        self.product = product
        self.customer = customer
        self.price = price
        self.date = date**
Enter fullscreen mode Exit fullscreen mode

Now, imagine you want to store and retrieve order data from a key-value database. Luckily, its interface accepts and return dictionaries, so you need to convert your object into a dictionary:

**def serialize_order(order):
    return {
        'product': order.product,
        'customer': order.customer,
        'price': order.price,
        'date': order.date
    }**
Enter fullscreen mode Exit fullscreen mode

And if you want to get some data from that database, you can get the dict data and turn that into your Order object:

**def deserialize_order(order_data):
    return Order(
        product=order_data['product'],
        customer=order_data['customer'],
        price=order_data['price'],
        date=order_data['date'],
    )**
Enter fullscreen mode Exit fullscreen mode

This is pretty straightforward to do with simple data, but when you need to deal with complex objects made of complex attributes, this approach doesn’t scale well. You also need to handle the validation of different types of fields, and that’s a lot of work to do manually.

That’s where frameworks’ serializers are handy. They allow you to create serializers with little boilerplates that will work for your complex cases.

If you are interested in learning more about Django and Python then I recommend taking a look at the resources below:

Get the Book: Django web development

Django comes with a serialization module that allows you to “translate” Models into other formats:

**from django.core import serializers**

**serializers.serialize('json', Order.objects.all())**
Enter fullscreen mode Exit fullscreen mode

It covers the most-used cases for web applications, such as JSON, YAML, and XML. But you can also use third-party serializers or create your own. You just need to register it in your settings.py file:

***# settings.py*
SERIALIZATION_MODULES = {
    'my_format': appname.serializers.MyFormatSerializer,
}**
Enter fullscreen mode Exit fullscreen mode

To create your own MyFormatSerializer, you need to implement the .serialize() method and accept a queryset and extra options as params:

**class MyFormatSerializer:
    def serialize(self, queryset, **options):
        *# serious serialization happening***
Enter fullscreen mode Exit fullscreen mode

Now you can serialize your queryset to your new format:

**from django.core import serializers**

**serializers.serialize('my_format', Order.objects.all())**
Enter fullscreen mode Exit fullscreen mode

You can use the options parameters to define the behavior of your serializer. For example, if you want to define that you’re going to work with nested serialization when dealing with ForeignKeys or you just want that data to return its primary keys, you can pass a flat=True param as an option and deal with that within your method:

**class MyFormatSerializer:
    def serializer(self, queryset, **options):
        if options.get('flat', False):
            *# don't recursively serialize relationships*
        *# recursively serialize relationships***
Enter fullscreen mode Exit fullscreen mode

One way to use Django serialization is with the loaddata and dumpdata management commands.

DRF serializers

In the Django community, the Django REST framework (DRF) offers the best-known serializers. Although you can use Django’s serializers to build the JSON you’ll respond to in your API, the one from the REST framework comes with nice features that help you deal with and easily validate complex data.

In the Order example, you could create a serializer like this:

**from restframework import serializers**

**class OrderSerializer(serializers.Serializer):
    product = serializers.CharField(max_length=255)
    customer = serializers.CharField(max_lenght=255)
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    date = serializers.DateField()**
Enter fullscreen mode Exit fullscreen mode

And easily serialize its data:

**order = Order('pen', 'renato', 10.50, date.today())
serializer = OrderSerializer(order)**

**serializer.data
*# {'product': 'pen', 'customer': 'renato', 'price': '10.50', 'date': '2020-08-16'}***
Enter fullscreen mode Exit fullscreen mode

To be able to return an instance from data, you need to implement two methods — create and update:

**from rest_framework import serializers**

**class OrderSerializer(serializers.Serializer):
    product = serializers.CharField(max_length=255)
    customer = serializers.CharField(max_length=255)
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    date = serializers.DateField()**

 **   def create(self, validated_data):
        *# perform order creation*
        return order**

 **   def update(self, instance, validated_data):
       *# perform instance update*
       return instance**
Enter fullscreen mode Exit fullscreen mode

After that, you can create or update instances by calling is_valid() to validate the data and save() to create or update an instance:

**serializer = OrderSerializer(**data)
*## to validate data, mandatory before calling save*
serializer.is_valid()
serializer.save()**
Enter fullscreen mode Exit fullscreen mode

Model serializers

When serializing data, you often need to do it from a database, therefore, from your models. A ModelSerializer, like a ModelForm, provides an API to create serializers from your models. Suppose you have an Order model:

**from django.db import models
**

**class Order(models.Model):
    product = models.CharField(max_length=255)
    customer = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    date = models.DateField()**
Enter fullscreen mode Exit fullscreen mode

You can create a serializer for it like this:

**from rest_framework import serializers
**

**class OrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = Order
        fields = '__all__'**
Enter fullscreen mode Exit fullscreen mode

Django automatically includes all model fields in the serializer and creates the create and update methods.

Using serializers in class-based views (CBVs)

Like Forms with Django’s CBVs, serializers integrate well with DRFs. You can set the serializer_class attribute so that the serializer will be available to the view:

**from rest_framework import generics
**

**class OrderListCreateAPIView(generics.ListCreateAPIView):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer**
Enter fullscreen mode Exit fullscreen mode

You can also define the get_serializer_class() method:

**from rest_framework import generics
**

**class OrderListCreateAPIView(generics.ListCreateAPIView):
    queryset = Order.objects.all()

    def get_serializer_class(self):
        if is_free_order():
            return FreeOrderSerializer
        return OrderSerializer**
Enter fullscreen mode Exit fullscreen mode

There are other methods in CBVs that interact with serializers. For example, get_serializer() returns an already-instantiated serializer, while get_serializer_context() returns the arguments you’ll pass to the serializer when creating its instance. For views that create or update data, there are create and update that validate the data with the is_valid method to be saved, and perform_create and perform_update that call the serializer's save method.

Reference links:


Other Dev Posts:

Discussion (0)

pic
Editor guide