Serializers & ViewSets
In Django REST Framework, a serializer converts model instances to and from JSON — validating incoming data and shaping outgoing data — while a ViewSet bundles the standard list, create, retrieve, update, and delete actions into one class that a router can wire up to URLs automatically.
Learn Serializers & ViewSets in our free Django course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Django course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll build a ModelSerializer for a model, expose full CRUD through a ModelViewSet, and let a DefaultRouter generate all the URLs so you write almost no routing code by hand.
A serializer is the translator between your Django models and the JSON your API speaks. Going out , it turns a model instance into a dictionary of primitive values ready to become JSON. Coming in , it takes raw request data, validates it, and turns it back into a saved model instance.
The fastest way to write one is the ModelSerializer . You point it at a model and list the fields you want in an inner Meta class, and it generates the field definitions plus create() and update() for you.
A ViewSet groups related views into a single class. The ModelViewSet goes further: give it a queryset and a serializer_class and it provides every CRUD action — list , create , retrieve , update , partial_update , and destroy — automatically.
The ViewSet uses the serializer_class for both directions: it serializes the queryset on the way out and validates request data on the way in, calling .is_valid() and .save() for you.
Writing URL patterns for every CRUD action by hand is tedious. A DefaultRouter inspects a registered ViewSet and generates all of them for you, plus a browsable API root at the base URL.
From that single register() call, the router builds these URLs:
The basename argument controls the names DRF uses when reversing URLs (for example article-list and article-detail ). You can omit it when the ViewSet has a queryset , but passing it explicitly is good practice.
Fill in the blank with the method name you must call before reading validated data or saving. In DRF this is the serializer method that runs all validation.
❌ AssertionError: cannot access serializer.data before is_valid()
You created the serializer with data= but tried to read validated values before validating.
✅ Fix: call serializer.is_valid() first, then read serializer.validated_data or call serializer.save() .
You registered the ViewSet on the router but never added the router's URLs to urlpatterns .
✅ Fix: include them — urlpatterns = router.urls (or path("", include(router.urls)) ).
The field exists on the model but was never listed in the serializer's Meta.fields .
✅ Fix: add the field name to Meta.fields (or use fields = "__all__" to include every model field).
Simulate the full deserialize-and-save flow DRF runs: validate the incoming data, then either save it or report the errors.
Lesson 20 complete — your API writes itself!
You can now build a ModelSerializer with an inner Meta, serialize objects out and deserialize data in, validate with is_valid() before save(), expose full CRUD with a ModelViewSet, and auto-generate URLs with a DefaultRouter.
🚀 Up next: Signals — run code automatically when models are saved, deleted, or changed.
Practice quiz
What does a serializer do in Django REST Framework?
- Converts model instances to and from JSON
- Routes URLs to views
- Runs database migrations
- Renders HTML templates
Answer: Converts model instances to and from JSON. A serializer translates between model instances and JSON, validating data both ways.
Where do you declare the model and fields on a ModelSerializer?
- In the __init__ method
- In an inner Meta class
- In settings.py
- In a urls.py entry
Answer: In an inner Meta class. A ModelSerializer reads model and fields from its inner Meta class.
Which serializer method must you call before reading validated_data or saving?
- clean()
- validate_all()
- is_valid()
- full_clean()
Answer: is_valid(). is_valid() runs validation and populates validated_data and errors; it must run first.
What advantage does ModelSerializer have over a plain Serializer?
- It is faster at runtime only
- It encrypts data
- It skips validation
- It builds fields and create()/update() automatically from the model
Answer: It builds fields and create()/update() automatically from the model. ModelSerializer generates field definitions plus create() and update() from the model.
Which class provides full CRUD actions from a queryset and serializer_class?
- APIView
- ModelViewSet
- TemplateView
- Serializer
Answer: ModelViewSet. ModelViewSet supplies list, create, retrieve, update, partial_update, and destroy.
Which HTTP method maps to the ViewSet 'create' action on the list URL?
- POST
- GET
- PUT
- DELETE
Answer: POST. POST to the collection URL maps to the create action.
Which router also generates a browsable API root view?
- SimpleRouter
- BaseRouter
- DefaultRouter
- PlainRouter
Answer: DefaultRouter. DefaultRouter adds an API root view linking to every registered endpoint.
What is raised if you access validated_data before calling is_valid()?
- A ValueError
- A 404 response
- Nothing happens
- An AssertionError
Answer: An AssertionError. Accessing validated_data before is_valid() raises an AssertionError.
How do you register a ViewSet with a router?
- router.register(r'articles', ArticleViewSet)
- router.add(ArticleViewSet)
- router.include(ArticleViewSet)
- router.route('articles')
Answer: router.register(r'articles', ArticleViewSet). router.register(prefix, ViewSet, basename=...) wires the ViewSet to generated URLs.
Which Meta.fields value includes every model field?
- *
Setting fields = '__all__' includes every field on the model.