Django-Rest-Framework CRUD operations using Generic Views

In this article, we will briefly see how to implement CRUD operations in Django-Rest-Framework using generic class-based views.

Models

In this example, we'll be using only one model, which is very simple.

from django.db import models


class Product(models.Model):
    name = models.CharField(max_length=50)
    price = models.DecimalField(max_digits=5, decimal_places=2)

    def get_discounted_price(self, percent):
        return "%.2f" % (float(self.price) * (1 - percent / 100))

    def __str__(self):
        return self.name

So, we have a table called Product with two columns in it name, and price, also we have a method to calculate a new discounted price called get_discounted_price.

Serializers

Again, we have only one serializer in this example.

from rest_framework import serializers
from .models import Product


class ProductSerializer(serializers.ModelSerializer):
    sale_price = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = Product
        fields = ["id", "name", "price", "sale_price"]

    def get_sale_price(self, obj):
        return obj.get_discounted_price(5)

Notice that, we have a Serializer Method Field, we discussed that in the previous article. In short, we used it to add a new field in the data coming through API to the client side, and that field is sale_price.

Look at the previous article for a little more information on that.

Django-Rest-Framework: How to add a calculated field into the serializer (using SerializerMethodField)

URLs

Before we work on views, let's add the URLs first, because they are very simple, and easy to do.

from django.urls import path


from .views import (
    ProductDetailAPIView,
    ProductListCreateAPIView,
    ProductUpdateAPIView,
    ProductDeleteAPIView,
)


urlpatterns = [
    path("", ProductListCreateAPIView.as_view()),
    path("<int:pk>/update/", ProductUpdateAPIView.as_view()),
    path("<int:pk>/delete/", ProductDeleteAPIView.as_view()),
    path("<int:pk>/", ProductDetailAPIView.as_view()),
]

Also, we have the base URLs file, which includes this file with prefix api/products/ .

Views

Finally, here we will add the views.

First, here are a few import statements, just in case!

from rest_framework import generics
from .models import Product
from .serializers import ProductSerializer

ListCreateAPIView

This API View is used for both, List and Create.

List the objects if the request method is GET, and create an object if the request method is POST.

class ProductListCreateAPIView(generics.ListCreateAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer

    def perform_create(self, serializer):
        # print(serializer.validated_data)
        return super().perform_create(serializer)

Play around with it to know more stuff.

Here, we do not really need perform_create method, as it is not doing anything, but you can customize the view through that method easily.

And let's see this in action in the browsable API below.

Here it shows the list of the objects we have in the database.

And there is a form below to create a new object.

UpdateAPIView

Here's our update API view.

class ProductUpdateAPIView(generics.UpdateAPIView):
    queryset = Product.objects.all()  # or get_queryset

    serializer_class = ProductSerializer

    def perform_update(self, serializer):
        # we can play around with serializer here
        name = serializer.validated_data.get("name")
        if "x" not in name:
            name = "x" + name
            serializer.validated_data["name"] = name
        return super().perform_update(serializer)

Here, we have a method called perform_update, which we do not really need, but we can use it to customize the view a little bit, for example, we are adding x in the beginning of the name if it is not in the name.

So, if we update the name to PS5, it will save it as xPS5.

DestroyAPIView

Deleting stuff is very simple, and most of the code is the same.


class ProductDeleteAPIView(generics.DestroyAPIView):
    queryset = Product.objects.all()  # or get_queryset

    serializer_class = ProductSerializer

    def perform_destroy(self, instance):
        return super().perform_destroy(instance)

Here, we have a method perform_destroy, which is doing nothing, but if we'd like, we can do some checks before deleting the stuff.

Let's delete the product with id=3.

The product is deleted!

RetriveAPIView

This view is simply used to get an object through the lookup field (like primary key pk).

class ProductDetailAPIView(generics.RetrieveAPIView):
    queryset = Product.objects.all()  # or get_queryset
    # lookup_field = "pk" # default queryset lookup

    serializer_class = ProductSerializer

It simply shows details for a single object.

That's all for now, next time we will see some more advance stuff.

So, grab a coffee or two for the next article.

Thanks!

Did you find this article valuable?

Support Shubham Patel by becoming a sponsor. Any amount is appreciated!