Django DRF Cheat Sheet


Django DRF Cheat Sheet

Here's the PDF: Django DRF Cheat Sheet v1.3, and HTML

Welcome. This is a guide to the parts of DRF (Django Rest Framework) that I routinely forget or need to reference periodically. This is not a learning resource nor a tutorial, but intended for those already programming in DRF.
- Charles Thayer

Got constructive feedback? Let me know
(Want a new or different cheat sheet? DRF Basics, Django, CBV, Firebase?)

Info

About

I've been using Django and DRF off and on for way too long. Lately, I've been working as the CTO of a startup in San Francisco that built a mobile app for "managed messaging" for businesses and professionals. That project incorporated a fair amount of API/Javascript communication, which lead me to take notes on the parts of DRF that I needed to review periodically.

I hope you find it helpful and provide constructive feedback. If enough people do, I'll continue to update and distribute it. Thanks.

-- Charles Thayer (thayer at b2si com)

Serializers

Serialize:

# Object instance -> Data dict
s = Serializer(instance)
s.data

Deserialize (create):

# dict -> Object
s = Serializer(data={..})
s.is_valid()
instance = s.save()

Validation:

s = Serializer(data={..})
if s.is_valid(raise_exception=False):
  s.validated_data
else:
  s.errors  # dict(field=[problems..])

Update:

s = Serializer(instance, validated_data, partial=True)
new = s.save()

Serializer Classes:

class SimpleSerializer(serializers.Serializer):
  name = serializers.CharField(max_length=128)
  user = UserSerializer(required=false)  # nested
  ...

def create(self, validated_data):
  kwargs = self.context['view'].kwargs
  ...
  return instance

def update(self, instance, validated_data):
  # if self.partial
  ...
  return instance

def save(self, **kwargs):
  # instance = super().save(**kwargs)
  nm = self.validated_data.get('name')
  ...
  instance = model_object.save()
  return instance

# def validate_(self, name):
def validate_name(self, name):
  if not name:
    raise serializers.ValidationError('Name required')
  ...
  return name

def validate(self, data):
  nm = data.get('name')
  if not nm:
    raise serializers.ValidationError({'name': ..})
  ...
  return validated_data

class DbSerializer(serializers.ModelSerializer):
  class Meta:
    model = DbModel
    fields = [..]
    list_serializer_class = DbListSerializer
  def to_representation(self, obj) → Dict
  def to_internal(self, data) → Dict # validated

Basics

Serializers

CreateSerializer(data={..}); s.save(): Object
SerializeSerializer(instance); s.data: Dict
UpdateSerializer(instance, data={..}, partial=True)
SetSerializer(instance, data={..})

Serializer Fields:

  • Common: CharField, UUIDField, NullBooleanField, DateTimefield, JSONField, EmailField, ..
  • Special: SerializerMethodField, RelatedField, PrimaryKeyRelatedField, SlugRelatedField, HyperlinkedRelatedField..

Field Args

DefaultInputOutputNotes
read_onlyFalsenoyes
write_onlyFalseyesno
requiredTrueyesyesraise if missing
allow_nullFalseNone is allowed
default<value>setsIf set, don’t use the arg “required”
sourcethe python form of field access like "user.address.zip" (not double underscore) OR a callable name on the object like get_primary_phone()

Request

  • request.data - dict of (post, put, patch)
  • request.query_param (get)
  • request.user (django.contrib.auth.models.AnonymousUser)
  • request.auth (usually a model instance)
  • HTTP stuff: request.method (e.g. GET), .content_type (e.g. application/json), .META, .headers, .path

view() functions

# urls.py
urlpatterns = [
  path(r'viewfn//', views.my_view_fn),
]
# views.py
from django.http import JsonResponse
...
  def my_view_fn(request, arg1=None):
    if request.method == ‘POST’:
      return JsonResponse({}, status=201)

Testing

from rest_framework.test import APIClient, APITestCase

class MyTests(APITestCase):
  def test_basics(self):
    client = APIClient()
    response = client.post(
      f'/viewtest/{arg1}', data={..})
    assert response.status_code == 200
    assert response.json().get(‘name’) == name

Views

class SimpleView(APIView):
  def post(self, request, *args, **kwargs):
    request.data.get(‘name’)
    return Response(..)
  def get(self, request, *args, **kwargs):
    request.query_params.get(‘name’)
    ...
  def patch(self, request, *args, **kwargs):
    ...
  def delete(self, request, *args, **kwargs):
    ...

ViewSets

ViewSets (ModelViewSets)

from rest_framework import permissions

class SimpleViewSet(ViewSet):  # ModelViewSet
  serializer_class = SimpleSerializer
  # queryset = SimpleModel.objects.all()
  lookup_field = 'field'
  authentication_classes = (..,)
  permissions_classes = (permissions.IsAuthenticated,)
  # permissions_classes = (permissions.AllowAny,)
  # filter_backends = (..,)
   def create(self, request, *args, **kwargs):
      return Response(..)

  def update(self, request, *args, **kwargs):
  def partial_update(self, request, *args, **kwargs):
  def destroy(self, request, *args, **kwargs):
  def retrieve(self, request, *args, **kwargs):
  def list(self, request, *args, **kwargs):

  def get_queryset(self):
    # related to self.queryset
    data = self.request.data
    qp = self.request.query_params
    kwargs = self.kwargs  # args for view

  def get_object(self): → instance
    # see self.lookup_field

  def get_serializer(self):
  def get_serializer_context(self):
    ...
    return dict(request=..., view=...

  @detail_router([‘GET’, ‘POST’])
  def custom(request, *args, **kwargs):
    ...
# urls.py
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(
    r'viewset',
    example.SimpleViewSet,
    basename='Simple’
)
            
urlpatterns = [
    path(r‘’, include(router.urls)),
    ...