In this post, we are going to learn about function based views in Django. Django has two types of views; function-based views (FBVs), and class-based view (CBVs). Django originally started out with only FBVs, but then added CBVs as a way to templatize functionality so that you didn’t have to write boilerplate (i.e. the same code) code over and over again.
Setup for Function Based Views
Let’s create a project first and setup URLs (skip this section if you are already aware of this setup).
#Create a fresh virtual environment
mkvirtualenv env (On creating, env will be activated automatically. Activate it if you navigate to a new tab.)
pip install Django
#Go to your favourite directory and create a new project
django-admin startproject drinks
#Important step. Perform all the operations in this directory. When I say ‘project_template’ directory in future, it points to the directory present inside this, i.e,. project_directory/project_directory.
Lets create a sample app ‘core’.
python manage.py startapp core
Setting Up Project Settings.py
Add ‘core’ + rest_framework to installed apps in your settings.py files
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'core', 'rest_framework' ]
Working with models
Let’s build the model for our API. In this example, we are going to see how to store drinks
We are going to capture name and description details of each individual drink.
Add the below code to the models.py inside the core folder.
from django.db import models # Create your models here. class Drink(models.Model): name=models.CharField(max_length=200) description = models.CharField(max_length=500) def __str__(self): return self.name+" "+self.description
Now its time to create a Serializers for API.
Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON, XML or other content types. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.
First, create a file called serializers.py and add the below code.
from rest_framework import serializers from .models import Drink class DrinkSerializer(serializers.ModelSerializer): class Meta: model= Drink fields = ['id', 'name', 'description']
in the fields, sections above you can use __all__ to add all the columns for serializations. If you want to capture individual ones you can pass a list of column names.
Updating the views .py
Finally, let’s create Views.py
First we need to be able to fetch all the results by performing a GET and also should be able to add a new drink record.
The below code helps you fetch all records on GET and add new student details. The core of this functionality is the api_view decorator, which takes a list of HTTP methods that your view should respond to. For example, this is how you would write a very simple view that just manually returns some data:
@api_view(['GET','POST']) def drink_list(request): if request.method == 'GET': students = Drink.objects.all() serializers = DrinkSerializer(drinks,many=True) return Response(serializers.data) elif(request.method == 'POST'): serializer = DrinkSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data,status=status.HTTP_201_CREATED) return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
In the next scenario we are going to see how to work with individual student records using GET,PUT,DELETE
The PK here is the primary key column in your database which is ID in our case.
api_view(['GET','PUT','DELETE']) def drink_detail(request,pk): try: student = Drink.objects.get(pk=pk) except Drink.DoesNotExist: return Response(status=status.HTTP_404_NOT_FOUND) if request.method == 'GET': serializer = DrinkSerializer(Drink) return Response(serializer.data) elif request.method == 'PUT': serializer = DrinkSerializer(Drink,request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST) elif request.method == 'DELETE': Drink.delete() return Response(status=status.HTTP_204_NO_CONTENT)
Make sure to import all the necessary modules
from .models import Drink from .serializers import DrinkSerializer from django.http import Http404 from rest_framework.response import Response from rest_framework import status from rest_framework.decorators import api_view
Last we will add the URLs to make sure we are able to hit it via the endpoints
Add/update the URL patterns in urls.py in StudentService
urlpatterns = [ path('',views.drink_list), path('<int:pk>/',views.drink_detail), ]
This function based views is very easy to implement and it’s very useful but the main disadvantage is that on a large Django project, usually a lot of similar functions in the views. If all objects of a Django project usually have CRUD operations so this code is repeated again and again unnecessarily and this was one of the reasons that the class-based views and generic views were created for solving that problem.
We saw how to use the function based views in this post while there are other types of views as well which we will cover in upcoming posts. if you want to know if function based views are best among all then it all depends on the context and the needs. As I mentioned in the beginning of this post, class-based views does not replace function-based views. There are cases where function-based views are better. In other cases, class-based views are better.