Open In App

Pass Extra Arguments to Serializer Class in Django Rest Framework

Last Updated : 01 Oct, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

Django Rest Framework (DRF) is a powerful toolkit for building web APIs. It provides serializers that translate complex data types such as Django queryset into native Python data types, which can then be rendered into JSON or other content types. However, there are cases when we need to pass extra arguments from our view to a serializer. For example, we may need to pass values from a query string, dynamic data, or user-specific context that isn't part of the model. This article walks through the process of passing extra arguments to a DRF serializer from a ViewSet by building a simple Django project and illustrating the key concepts

Pass Extra Arguments to Serializer Class in Django Rest Framework

Step 1: Set Up a Django Project

Run the following commands to create and set up our Django project:

django-admin startproject myproject
cd myproject
python manage.py startapp myapp

Make sure we add myapp to the INSTALLED_APPS in our project’s settings:

Python
INSTALLED_APPS = [
    # other apps...
    'myapp',
    'rest_framework',
]
oppp
Django Project Structure

Step 2: Define a Model

For demonstration purposes, let's create a simple model in myapp/models.py:

Python
from django.db import models

class OneZero(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()

Run migrations to apply this model to the database:

python manage.py makemigrations
python manage.py migrate

Enter in the Python shell using below command and insert some data in database

python manage.py shell

Now We can insert data using Django ORM queries.

Python
# Import the OneZero model
from myapp.models import OneZero

# Insert a new instance using the save() method
one_zero_instance = OneZero(name="Test Name", description="This is a test description")
one_zero_instance.save()

# Insert a new instance using the create() method (shortcut for saving)
OneZero.objects.create(name="Sample Name", description="Sample description")

# Prepare a list of multiple instances to insert in bulk
one_zero_list = [
    OneZero(name="Item 1", description="Description for Item 1"),
    OneZero(name="Item 2", description="Description for Item 2"),
    OneZero(name="Item 3", description="Description for Item 3"),
]

# Insert multiple instances at once using bulk_create()
OneZero.objects.bulk_create(one_zero_list)

# Retrieve all instances from the OneZero table
OneZero.objects.all()

# Filter instances where name is "Test Name"
OneZero.objects.filter(name="Test Name")

# Exit the shell
exit()
orm-query
Django Shell

Step 3: Define a Serializer

In myapp/serializers.py, define a serializer for the OneZero model. To handle extra arguments from the view, override the __init__ method and use the context argument, which DRF provides to pass additional data to the serializer.

Python
from rest_framework import serializers
from .models import OneZero

class OneZeroSerializer(serializers.ModelSerializer):
    # Custom field not present in the model
    alternate_name = serializers.SerializerMethodField()

    def __init__(self, *args, **kwargs):
        # Capture any additional arguments
        self.realpart = kwargs.pop('realpart', None)
        super(OneZeroSerializer, self).__init__(*args, **kwargs)

    def get_alternate_name(self, obj):
        # Use the extra argument passed from the view
        return f'Alternate {self.realpart}' if self.realpart else ''

    class Meta:
        model = OneZero
        fields = ('id', 'name', 'description',  'alternate_name')

Step 4: Define the ViewSet

In myapp/views.py, define a OneZeroViewSet that passes an extra argument (realpart) to the serializer based on query parameters. In this viewset: The get_serializer method is overridden to capture query parameters and pass them to the serializer as an additional argument.

Python
from rest_framework import viewsets
from .models import OneZero
from .serializers import OneZeroSerializer

class OneZeroViewSet(viewsets.ModelViewSet):
    queryset = OneZero.objects.all()

    def get_serializer(self, *args, **kwargs):
        # Extract 'realpart' from query parameters and pass it to the serializer
        realpart = self.request.query_params.get('realpart')
        kwargs['realpart'] = realpart
        return OneZeroSerializer(*args, **kwargs)

Step 5: Configure URLs

Finally, define the URLs in myapp/urls.py:

Python
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import OneZeroViewSet

router = DefaultRouter()
router.register(r'onezero', OneZeroViewSet)

urlpatterns = [
    path('', include(router.urls)),
]

Include the myapp URLs in the main myproject/urls.py:

Python
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('myapp.urls')),
]

Step 6: Test the Implementation

To test this, run the Django development server:

python manage.py runserver

Make a GET request to the OneZeroViewSet endpoint with the realpart query parameter:

http://127.0.0.1:8000/onezero/?realpart=1

The serializer will output a field alternate_name that uses the value of realpart passed via the query string.

output1
realpart query = 1
output
realpart query = 2

Conclusion

Passing extra arguments from a view to a serializer in Django Rest Framework is essential for handling dynamic fields or adding context-dependent logic. This can be done using DRF's context feature or by overriding the __init__ method in the serializer to accept custom arguments. By capturing the required information in the viewset and passing it to the serializer, we can handle any additional data our API needs in a clean and structured way.


Next Article
Practice Tags :

Similar Reads