Django REST Framework Q&A
Django REST framework interview questions with there answers
Here are some common Django REST Framework (DRF) interview questions along with their
answers:
1. What is Django REST Framework (DRF)?
Answer: Django REST Framework (DRF) is a powerful and flexible toolkit for building Web APIs. It
allows you to create RESTful APIs using Django, offering features such as serialization, authentication,
and view sets, making API development straightforward.
2. What are serializers in Django REST Framework?
Answer: Serializers in DRF are used to convert complex data types such as Django models or
QuerySets into JSON or XML format. They also perform deserialization, i.e., transforming incoming
JSON or XML into Django objects for use in the backend.
python
from rest_framework import serializers
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['title', 'author']
3. What is the difference between `APIView` and `ViewSet` in DRF?
Answer:
APIView: A base class for all views in DRF. It provides the most control but requires more work,
such as manually defining `get()`, `post()`, etc.
ViewSet: It automatically defines routes for common actions like list, create, retrieve, update,
and delete (CRUD operations), reducing code duplication.
python
# APIView Example
class BookList(APIView):
def get(self, request):
books = Book.objects.all()
serializer = BookSerializer(books, many=True)
return Response(serializer.data)
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 1/18
# ViewSet Example
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
4. What are mixins in DRF?
Answer: Mixins in DRF are reusable classes that provide default implementations for actions like
`list`, `create`, `retrieve`, `update`, and `destroy`. You can combine these mixins with `APIView` to
create views for basic CRUD operations.
python
from rest_framework import mixins
from rest_framework.generics import GenericAPIView
class BookListCreateView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
5. What is a QuerySet and how is it used in DRF?
Answer: A QuerySet in Django represents a collection of objects from the database. In DRF, QuerySets
are used in views to fetch data, which is then serialized before sending it to the client.
python
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
6. How does authentication work in Django REST Framework?
Answer: DRF supports multiple authentication methods like Basic Authentication, Token
Authentication, Session Authentication, and OAuth. You can configure the authentication classes in
your settings or views.
python
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 2/18
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
7. What is pagination in DRF and how can you implement it?
Answer: Pagination in DRF refers to splitting a large list of results into smaller "pages". You can define
global pagination settings or customize them per view.
python
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
}
# Alternatively, you can add pagination to a specific view:
from rest_framework.pagination import LimitOffsetPagination
class BookList(generics.ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = LimitOffsetPagination
8. What are permissions in DRF?
Answer: Permissions in DRF define the level of access a user has to a resource. Common permissions
include `IsAuthenticated`, `IsAdminUser`, and custom permissions.
python
from rest_framework.permissions import IsAuthenticated
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = [IsAuthenticated]
9. What is the difference between `@api_view` and `APIView`?
Answer:
`@api_view`: A function-based view decorator in DRF, used for simpler use cases.
`APIView`: A class-based view that offers more flexibility and scalability.
python
# Function-based view with @api_view
from rest_framework.decorators import api_view
@api_view(['GET'])
def book_list(request):
books = Book.objects.all()
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 3/18
serializer = BookSerializer(books, many=True)
return Response(serializer.data)
10. What are throttling and rate-limiting in DRF?
Answer: Throttling is used to control the rate of requests a client can make to an API. You can set
different throttling policies, like per-user, per-anonymous user, etc.
python
# settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.UserRateThrottle',
'rest_framework.throttling.AnonRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'user': '100/day',
'anon': '10/hour',
}
}
11. How can you handle exceptions in Django REST Framework?
Answer: DRF provides custom exception handling through the `@api_view` decorator or class-based
views using the `handle_exception` method. You can also use middleware or define custom exception
handling globally.
python
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
response = exception_handler(exc, context)
if response is not None:
response.data['status_code'] = response.status_code
return response
# settings.py
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}
12. How do you perform filtering in Django REST Framework?
Answer: DRF provides built-in support for filtering using the `django-filter` package. You can filter
QuerySets based on specific fields in your views or use filter backends.
python
from django_filters.rest_framework import DjangoFilterBackend
class BookViewSet(viewsets.ModelViewSet):
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 4/18
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['author', 'published_date']
These questions cover various aspects of the Django REST Framework, from basic to intermediate
topics. Interviewers often focus on how well you can explain concepts and apply them in practical
situations.
more questions
Thought for a second
Certainly! Here are additional Django REST Framework (DRF) interview questions along with their
comprehensive answers:
13. What is the purpose of `BrowsableAPIRenderer` in DRF?
Answer: `BrowsableAPIRenderer` is a renderer class in DRF that provides a web-browsable interface for
your API. It allows developers and users to interact with the API through a user-friendly HTML
interface, making it easier to test endpoints without the need for external tools like Postman.
python
# settings.py
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
}
14. Explain the concept of ViewSets vs Generic Views in DRF.
Answer:
ViewSets: Provide a way to combine the logic for a set of related views in a single class. They
automatically handle standard actions like `list`, `create`, `retrieve`, `update`, and `destroy`.
This reduces boilerplate code and simplifies URL routing using routers.
python
from rest_framework import viewsets
class AuthorViewSet(viewsets.ModelViewSet):
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 5/18
queryset = Author.objects.all()
serializer_class = AuthorSerializer
Generic Views: Offer base classes for building views with common patterns, such as listing or
creating objects. They provide more granular control compared to ViewSets and are suitable
when you need custom behavior.
python
from rest_framework import generics
class AuthorList(generics.ListCreateAPIView):
queryset = Author.objects.all()
serializer_class = AuthorSerializer
15. How do you handle nested serializers in DRF?
Answer: Nested serializers allow you to represent related objects within a serializer. This is useful for
displaying related data in a single API response.
python
from rest_framework import serializers
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', 'title']
class AuthorSerializer(serializers.ModelSerializer):
books = BookSerializer(many=True, read_only=True)
class Meta:
model = Author
fields = ['id', 'name', 'books']
To handle writable nested serializers (e.g., creating or updating related objects), you need to override
the `create` and `update` methods:
python
class AuthorSerializer(serializers.ModelSerializer):
books = BookSerializer(many=True)
class Meta:
model = Author
fields = ['id', 'name', 'books']
def create(self, validated_data):
books_data = validated_data.pop('books')
author = Author.objects.create(**validated_data)
for book_data in books_data:
Book.objects.create(author=author, **book_data)
return author
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 6/18
16. What is the role of Routers in DRF?
Answer: Routers in DRF automatically generate URL configurations for ViewSets, reducing the need to
manually define URL patterns for each action. They map HTTP methods to ViewSet actions like `list`,
`create`, `retrieve`, etc.
python
from rest_framework import routers
from myapp.views import BookViewSet
router = routers.DefaultRouter()
router.register(r'books', BookViewSet)
# urls.py
from django.urls import path, include
urlpatterns = [
path('', include(router.urls)),
]
17. How can you customize the default authentication in DRF?
Answer: You can customize authentication in DRF by:
1. Adding or Removing Authentication Classes: Modify the `DEFAULT_AUTHENTICATION_CLASSES` in
`settings.py`.
python
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.TokenAuthentication',
],
}
2. Creating Custom Authentication Classes: Subclass `BaseAuthentication` and implement the
`authenticate` method.
python
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from myapp.models import Token
class CustomTokenAuthentication(BaseAuthentication):
def authenticate(self, request):
token = request.headers.get('X-Custom-Token')
if not token:
return None
try:
user_token = Token.objects.get(key=token)
except Token.DoesNotExist:
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 7/18
raise AuthenticationFailed('Invalid token')
return (user_token.user, token)
Then, add your custom class to `DEFAULT_AUTHENTICATION_CLASSES`.
python
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'myapp.authentication.CustomTokenAuthentication',
],
}
18. What are Signals in Django, and how can they be used in DRF?
Answer: Signals in Django are a way to allow decoupled applications to get notified when certain
events occur. They are useful for executing certain actions automatically in response to events like
model creation, updates, or deletions.
Using Signals in DRF:
For example, you might want to send a notification or update related models whenever a new API
object is created.
python
# signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import Book
from myapp.notifications import send_new_book_notification
@receiver(post_save, sender=Book)
def notify_new_book(sender, instance, created, **kwargs):
if created:
send_new_book_notification(instance)
Connecting Signals: Ensure that the signals are connected when the app is ready.
python
# apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = 'myapp'
def ready(self):
import myapp.signals
19. Explain how to implement Versioning in DRF.
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 8/18
Answer: API versioning allows you to manage changes and updates to your API without disrupting
existing clients. DRF supports several versioning schemes:
1. URL Path Versioning: Include the version number in the URL.
python
# urls.py
from django.urls import path, include
urlpatterns = [
path('api/v1/', include('myapp.api.v1.urls')),
path('api/v2/', include('myapp.api.v2.urls')),
]
2. Query Parameter Versioning: Specify the version as a query parameter.
python
# settings.py
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.QueryParameterVersioning',
'ALLOWED_VERSIONS': ['1.0', '2.0'],
'DEFAULT_VERSION': '1.0',
}
Clients can request `?version=2.0`.
3. Header Versioning: Use custom headers to specify the version.
python
# settings.py
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.HeaderVersioning',
}
Clients can send `HTTP_X_API_VERSION: 2.0`.
4. Namespace Versioning: Utilize URL namespaces for different versions.
python
# urls.py
from django.urls import path, include
urlpatterns = [
path('api/', include(('myapp.api.v1.urls', 'v1'), namespace='v1')),
path('api/', include(('myapp.api.v2.urls', 'v2'), namespace='v2')),
]
Using Version in Views:
You can access the version in your views via `request.version`.
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 9/18
python
from rest_framework.views import APIView
from rest_framework.response import Response
class ExampleView(APIView):
def get(self, request, format=None):
version = request.version
return Response({'version': version})
20. How do you implement Caching in DRF?
Answer: Caching can improve the performance of your API by storing frequently accessed data. You
can implement caching in DRF using Django’s caching framework.
Steps to Implement Caching:
1. Configure Cache Backend: Define your cache settings in `settings.py`.
python
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
2. Use Cache Decorators: Apply caching decorators to your views.
python
from django.views.decorators.cache import cache_page
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['GET'])
@cache_page(60*15) # Cache for 15 minutes
def cached_book_list(request):
books = Book.objects.all()
serializer = BookSerializer(books, many=True)
return Response(serializer.data)
3. Cache at the ViewSet Level: Override the `list` method and apply caching.
python
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from rest_framework import viewsets
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
@method_decorator(cache_page(60*15))
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 10/18
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)
4. Use Third-Party Packages: Utilize packages like django-rest-framework-caching for more
advanced caching strategies.
21. What are Hyperlinked Serializers in DRF and how do they differ from standard
serializers?
Answer: HyperlinkedSerializers use hyperlinks to represent relationships between entities, whereas
ModelSerializers typically use primary keys.
Advantages of HyperlinkedSerializers:
More RESTful as they provide URLs to related resources.
Easier navigation of API endpoints.
Example:
python
from rest_framework import serializers
class AuthorSerializer(serializers.HyperlinkedModelSerializer):
books = serializers.HyperlinkedRelatedField(
many=True,
read_only=True,
view_name='book-detail'
)
class Meta:
model = Author
fields = ['url', 'id', 'name', 'books']
class BookSerializer(serializers.HyperlinkedModelSerializer):
author = serializers.HyperlinkedRelatedField(
queryset=Author.objects.all(),
view_name='author-detail'
)
class Meta:
model = Book
fields = ['url', 'id', 'title', 'author']
URL Configuration: Ensure that your routers are set up with appropriate view names.
python
from rest_framework import routers
from myapp.views import AuthorViewSet, BookViewSet
router = routers.DefaultRouter()
router.register(r'authors', AuthorViewSet)
router.register(r'books', BookViewSet)
urlpatterns = [
path('', include(router.urls)),
]
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 11/18
22. How do you implement Throttling in DRF and what types are available?
Answer: Throttling controls the rate of API requests to prevent abuse and ensure fair usage.
Types of Throttles:
1. UserRateThrottle: Limits the rate based on the authenticated user.
2. AnonRateThrottle: Limits the rate for anonymous users.
3. ScopedRateThrottle: Allows different throttle rates for different parts of the API.
Implementation Steps:
1. Configure Throttle Classes and Rates: Define in `settings.py`.
python
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.UserRateThrottle',
'rest_framework.throttling.AnonRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'user': '1000/day',
'anon': '100/day',
'burst': '200/minute',
}
}
2. Apply ScopedRateThrottle: Use scopes to define specific rates for different views.
python
from rest_framework.throttling import ScopedRateThrottle
from rest_framework import viewsets
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
throttle_classes = [ScopedRateThrottle]
throttle_scope = 'burst'
3. Custom Throttle Classes: Create custom throttle classes by subclassing `BaseThrottle`.
python
from rest_framework.throttling import BaseThrottle
class CustomThrottle(BaseThrottle):
def allow_request(self, request, view):
# Implement custom logic
return True
def wait(self):
return None
Then, add it to `DEFAULT_THROTTLE_CLASSES` or use it in specific views.
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 12/18
23. What is `django-filter` and how is it used in DRF?
Answer: `django-filter` is a Django application for allowing users to filter querysets dynamically
based on GET parameters. In DRF, it integrates seamlessly to provide robust filtering capabilities.
Installation:
bash
pip install django-filter
Configuration:
1. Add to Installed Apps:
python
INSTALLED_APPS = [
...
'django_filters',
]
2. Set Filter Backend in DRF Settings:
python
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}
Usage in Views:
python
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from myapp.models import Book
from myapp.serializers import BookSerializer
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['author', 'genre', 'published_date']
Creating Custom FilterSets:
python
import django_filters
from myapp.models import Book
class BookFilter(django_filters.FilterSet):
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 13/18
title = django_filters.CharFilter(lookup_expr='icontains')
published_date = django_filters.DateFromToRangeFilter()
class Meta:
model = Book
fields = ['author', 'genre', 'title', 'published_date']
Applying Custom FilterSet to ViewSet:
python
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [DjangoFilterBackend]
filterset_class = BookFilter
24. How do you handle file uploads in DRF?
Answer: Handling file uploads in DRF involves configuring serializers and views to accept and process
file data.
Steps to Handle File Uploads:
1. Define the Model:
python
from django.db import models
class Document(models.Model):
title = models.CharField(max_length=100)
file = models.FileField(upload_to='documents/')
2. Create the Serializer:
python
from rest_framework import serializers
from myapp.models import Document
class DocumentSerializer(serializers.ModelSerializer):
class Meta:
model = Document
fields = ['id', 'title', 'file']
3. Implement the View:
python
from rest_framework import viewsets
from myapp.models import Document
from myapp.serializers import DocumentSerializer
class DocumentViewSet(viewsets.ModelViewSet):
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 14/18
queryset = Document.objects.all()
serializer_class = DocumentSerializer
4. Configure URLs with Router:
python
from rest_framework import routers
from myapp.views import DocumentViewSet
router = routers.DefaultRouter()
router.register(r'documents', DocumentViewSet)
urlpatterns = [
path('', include(router.urls)),
]
5. Client-Side Upload: Use `multipart/form-data` to send files.
bash
curl -X POST -H "Content-Type: multipart/form-data" \
-F "title=Sample Document" \
-F "file=@/path/to/file.pdf" \
http://localhost:8000/documents/
Handling Large Files: For large file uploads, consider using chunked uploads or integrating with
cloud storage services like AWS S3.
25. What are Signals in DRF and how do they differ from Django Signals?
Answer: This appears to be a duplicate or confusion between DRF and Django signals. To clarify:
Django Signals: Django provides a built-in signal dispatcher that allows decoupled applications to get
notified when certain actions occur (e.g., model creation).
DRF Signals: DRF does not have its own signal system separate from Django’s. Instead, developers
use Django signals within DRF projects to handle events related to API operations.
Example Use Case: Using Django’s `post_save` signal to perform actions after an API creates a new
object.
python
from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import Book
@receiver(post_save, sender=Book)
def after_book_save(sender, instance, created, **kwargs):
if created:
# Perform action, e.g., send notification
pass
26. How can you implement Rate Limiting based on IP in DRF?
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 15/18
Answer: By default, DRF throttling can be based on user or anonymous access, but to implement rate
limiting based on IP, you can create a custom throttle class.
Steps to Implement IP-Based Throttling:
1. Create a Custom Throttle Class:
python
from rest_framework.throttling import SimpleRateThrottle
class IPRateThrottle(SimpleRateThrottle):
scope = 'ip'
def get_cache_key(self, request, view):
return self.get_ident(request) # IP address
2. Configure Throttle Rates: Add the custom throttle to `DEFAULT_THROTTLE_CLASSES` and define its
rate.
python
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'myapp.throttling.IPRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'ip': '100/day',
}
}
3. Apply Throttle to Views: Ensure that your views use the throttle classes.
python
from rest_framework import viewsets
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
throttle_classes = [IPRateThrottle]
Note: `get_ident(request)` retrieves the client’s IP address. Ensure your application correctly handles
cases where the app is behind proxies or load balancers by configuring `USE_X_FORWARDED_HOST` and
related settings.
27. Explain how to use JWT (JSON Web Tokens) with DRF.
Answer: JWT is a popular method for authenticating API requests. To use JWT with DRF, you typically
integrate the `djangorestframework-simplejwt` package.
Steps to Implement JWT Authentication:
1. Install the Package:
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 16/18
bash
pip install djangorestframework-simplejwt
2. Configure DRF to Use JWT:
python
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
3. Update URLs to Include JWT Endpoints:
python
from django.urls import path
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
path('api/token/', TokenObtainPairView.as
27th question answer again
Sure! Here's the answer again for the 27th question:
27. How do you handle nested serializers in DRF?
Answer: Nested serializers allow you to represent related objects within a serializer. This is useful for
displaying related data in a single API response.
Example of Nested Serialization:
python
from rest_framework import serializers
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', 'title']
class AuthorSerializer(serializers.ModelSerializer):
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 17/18
books = BookSerializer(many=True, read_only=True)
class Meta:
model = Author
fields = ['id', 'name', 'books']
Handling Writable Nested Serializers:
To handle writable nested serializers (e.g., creating or updating related objects), you need to override
the `create` and `update` methods in the parent serializer:
python
class AuthorSerializer(serializers.ModelSerializer):
books = BookSerializer(many=True)
class Meta:
model = Author
fields = ['id', 'name', 'books']
def create(self, validated_data):
books_data = validated_data.pop('books')
author = Author.objects.create(**validated_data)
for book_data in books_data:
Book.objects.create(author=author, **book_data)
return author
def update(self, instance, validated_data):
books_data = validated_data.pop('books')
instance.name = validated_data.get('name', instance.name)
instance.save()
# Update books
for book_data in books_data:
book = instance.books.get(id=book_data.get('id'))
book.title = book_data.get('title', book.title)
book.save()
return instance
In this example, the `AuthorSerializer` can create and update authors along with their associated
books by handling nested data properly.
ChatGPT can make mistakes. Check important info.
Printed using Save ChatGPT as PDF, powered by PDFCrowd HTML to PDF API. 18/18