Django rest framework - basics I wish to know before I started last project
Kuba
Posted on June 20, 2021
The idea is to gather all information how to set up API endpoints based on model in Django and create some kind of cheat sheet.
To make it work in Django, we need three things. Some kind of Model with serializer and the View. Then we plug it to url and voilà ! Let's make it step by step.
Model
Nothing fancy here, just an Article. Skip to the next point 😉.
// models.py
from django.db import models
from django.contrib.auth import get_user_model
UserModel = get_user_model()
class Article(models.Model):
author = models.ForeignKey(UserModel, on_delete=models.SET_NULL, null=True)
title = models.CharField(max_length=50)
text = models.CharField(max_length=100)
Serializer
Serializer is a class that will convert our model instance to JSON and back. I don't want to focus on how it works but below you can find some functionalities of rest_framework serializers
.
Do not specify all fields
Use __all__
when you want to serialize all fields
// serializers.py
from rest_framework import serializers
from .models import Article
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = "__all__"
{
"id": 1,
"title": "sample title 1",
"text": "sample article text",
"author": 1
}
Exclude
If you want to exclude single field (ex. password) you can use exclude = [list of fields to exclude ]
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
exclude = ["author"]
{
"id": 1,
"title": "sample title 1",
"text": "sample article text",
}
Depth
Response is supplied with author PK. If we want to get more details about fields specified as foreign key, use depth = 1
.
Then it will serialize one level more. If author model will have some foreign key field too and depth will be equal to 2, it will be serialized too.
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = "__all__"
depth = 1
{
"id": 1,
"title": "sample title 1",
"text": "sample article text",
"author": {
"id": 1,
"last_login": "2021-06-14T07:19:30.612463Z",
"is_superuser": true,
"username": "admin",
"first_name": "",
"last_name": "",
"email": "admin@example.com",
"is_staff": true,
"is_active": true,
"date_joined": "2021-06-14T07:13:58.546066Z",
"groups": [],
"user_permissions": []
}
}
Reverse Serialization
Imagine that you want to make serializer for User model and know what Articles he wrote. Since User Model hasn't any field like 'articles' and Article model has relation to User Model in 'author' field, we can specify fields in User Model serializer like:
fields = ("id", "all other fields", "article_set" )
For better understanding try it out in the Django shell.
>>> from django.contrib.auth import get_user_model
>>> UserModel = get_user_model()
>>> admin = UserModel.objects.all( )[0]
>>> admin
<User: admin>
>>> admin.email
'admin@example.com'
>>> admin.articles_set.all( )
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'User' object has no attribute 'articles_set'
>>> admin.article_set.all( )
<QuerySet [<Article: Article object (1)>, <Article: Article object (2)>, <Article: Article object (3)>]>
Views
To generate views for the model I will use generic views.
To make it work we need to create a class which will inherit from GenericViewSet
and classes that implements methods POST, GET, PUT, PATCH, DELETE.
from rest_framework.mixins import RetrieveModelMixin, ListModelMixin, UpdateModelMixin, CreateModelMixin, DestroyModelMixin
from rest_framework.viewsets import GenericViewSet
class ArticleView(GenericViewSet, ..... ):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
Don't forget to add serializer_class
field and queryset
field. Alternatively you can define get_queryset( )
method or get_serializer_class( )
.
List View
Adds method GET to our View to list all resources (queryset). To override or extend behavior use: .list(request, *args, **kwargs)
method.
GET localhost:8000/api/articles
// views.py
class ArticleView(GenericViewSet, ListModelMixin):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
Detail View (Retrieve view)
Adds method GET to our View which provides detail information about single entity. To override or extend behavior use: .retrieve(request, *args, **kwargs)
method.
GET localhost:8000/api/articles/{article pk}
// views.py
class ArticleView(GenericViewSet, RetrieveModelMixin):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
Update View
Adds two methods to our View. PUT and PATCH. Use PUT request to update all fields and PATCH request as partial update. To override or extend behavior use: .update(request, *args, **kwargs)" method or ".partial_update(request, *args, **kwargs)
for PATCH.
PUT localhost:8000/api/articles/{article pk}
body: data to update as json representation of obj.
PATCH localhost:8000/api/articles/{article pk}
body: data to update as json with fields we want to update
class ArticleView(GenericViewSet, UpdateModelMixin):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
Create View
Adds method POST to view. To override or extend behavior use: .create(request, *args, **kwargs)
method.
POST localhost:8000/api/articles
body: json representation of obj to create
class ArticleView(GenericViewSet, CreateModelMixin):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
Destroy View
Adds method DELETE to view. Provides deletion of model instance. To override or extend behavior use: .destroy(request, *args, **kwargs)
method.
DELETE localhost:8000/api/articles/{article pk}
class ArticleView(GenericViewSet, DestroyModelMixin):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
I will update this post when I will find something noteworthy. Maybe you have some idea? 😉
originally published at: jakubszwajka
Posted on June 20, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.