By Md. Sabuj Sarker | 8/22/2017 | General |Beginners

Working with Django views

Working with Django views

Django follows an MVC pattern. But until now we do not see any C in the system. Where is the controller and what is the controller in Django? A part of controller responsibility is carried out by the framework itself, and the rest is done by the views. In Django, View is the controller and template is the view compared with MVC. In more stricter sense Django uses an MTV (Model Template View) framework.

What is a view

A view is any callable that returns an instance of HttpResponse or its subclass. A view callable must also accept a positional parameter that is an instance of HttpRequest. A view is the block of code where things happen. In the request/response cycle of a web application the view is the place from where the response is sent back to the user. Along with the positional parameter of an HttpRequest object, a view can accept other positional or keyword Arguments. The parameters are determined by the URL pattern. The unnamed regex groups become positional arguments and named regex groups become keyword arguments.

Function based views

Any callable that accepts at least one positional parameter as HttpRequest and returns HttpResponse object can be used as view. We are using functions as views in all the examples we have seen in various articles until now. Let's flashback:

def a_view_function(request):
   return HttpResponse("Hi I am a being sent from a_view_function()")

As we have seen a lot of examples with function based views I am not going to waste your time discussing them much.

Detecting request methods and act accordingly

We must not respond the same way with GET and POST requests. There are also other request methods like HEAD, PUT, etc. So, how do we detect from inside the view which method was used to send the HTTP(S) request?

We can check request method from the method attribute on the HttpRequest instance passed to the view.

def a_view_function(request):
   if request.method == "GET":
       return HttpResponse("It was a get method")
   elif request.method == "POST":
       return HttpResponse("It was a post method")
   else:
       return HttpResponse("It was a nor get, neither post method")

Keeping logic of get method and post method request in one function is not a good idea when the application gets large. We should use class based views for this kind of problems.

View with parameters

No matter whether the view is a function based view, class based view or any other callable, it can accept extra parameters declared in the URL patterns. The RegEx groups inside URL pattern is used as positional parameters and the named groups are used as optional or keyword parameters. I already showed examples in a previous article.

Class based views

Class based views come with a lot of sweetness. The most important things that we can emphasize is the separation of concern and cleanness. During form processing we have to struggle a lot on checking whether a request is a get request or post request. Again, sometimes we also need to handle head request. If we develop a RESTful service then we have to implement a lot of them. Before going further in discussion, let's create a class based view first.

from django.views import View
from django.http import HttpResponse

class AClassBasedView(View):
   def get(self, request):
       return HttpResponse("This response is being served from a class based view")

   def post(self, request):
       return HttpResponse("We have received your form data and we are on the way to process it")

A class based view is a class that inherits from View class. For get request you need to define get() method on the class, for post request to be handled by the view you need to define post() method on the class. For other methods you need to define equivalent methods on the class for the request to be served properly. As with any type of view the class based views must also accept an HttpRequest object and return an HttpResponse object.

But there is a problem, we cannot directly add the class on the URL mapping.

The following is wrong:

url(r'^my-class-based-view$', AClassBasedView)

AClassBasedView is a class and it is not a callable object. But we do not need to worry. Django provides a helper method with View class to make a callable proxy to use a class based view. The method we need to use is as_view().as_view()` which will create a proxy and return a callable so that the class can be used as view without any problem. So, we code it like this:

url(r'^my-class-based-view$', AClassBasedView.as_view())

Remember that class based views and generic views are not the same. Many people confuse them. Generic view is implemented with the help of class based views and thus you can call them class based views, but you cannot call all class based views generic views.

Class based views with extra parameters

Just as function based views can be passed extra positional or keyword arguments, class based views can also accept those positional or keyword arguments without much change. You need to provide those parameters to the get(), post() etc. methods.

from django.views import View
from django.http import HttpResponse

class AClassBasedView(View):
   def get(self, request, product_id, product_status=None):
       return HttpResponse("This response is being served from a class based view")

   def post(self, request, product_id, product_status=None):
       return HttpResponse("We have received your form data and we are on the way to process it")



Any callable as view

I told you that any callable object can be used as view. Now, let's play with something in that area. To create a callable object we do not want to use a function and when we use class based views we do not want to call as_view() to convert it to a view.

The first and simplest way I want to show you is the lambda expression way:

# urls.py
from django.conf.urls import url
from django.http import HttpResponse

urlpatterns = [
   url(r'^callable-view$', lambda request: HttpResponse("I am a response from a lambda expression"))
]

Fire up your development server. Go to http://localhost:8000/callable-view to see the result:

I am a response from a lambda expression

Lambda expression is not that useful except in some a few use cases. We need more, we need something bigger. How do we make a custom object callable? An instance of any class can be made callable with the help of __call__() method defined on it.

# url.py
from django.conf.urls import url
from django.http import HttpResponse
from app1.views import CallableObjectClass

urlpatterns = [
   url(r'^callable-view$', lambda request: HttpResponse("I am a response from a lambda expression")),
   url(r'^callable-view-2$', CallableObjectClass())
]



View

# views.py
from django.http import HttpResponse

class CallableObjectClass:
   def __call__(self, request):
       return HttpResponse("This response is being sent by a object that is callable")



Go to the url http://localhost:8000/callable-view-2 to see the following result:

This response is being sent by a object that is callable



In a future article we will also learn how to protect your views. Every view can be protected with decorators form external users or public access. Again we can restrict users of various permission levels to access any particular view. We can do this with built in decorators, custom decorators, or inside views with the help of pure Python code.

 

*Stop by the homepage to search and compare SDKs, Dev Tools, and Libraries.

By Md. Sabuj Sarker | 8/22/2017 | General

{{CommentsModel.TotalCount}} Comments

Your Comment

{{CommentsModel.Message}}

Recent Stories

Top DiscoverSDK Experts

User photo
3355
Ashton Torrence
Web and Windows developer
GUI | Web and 11 more
View Profile
User photo
3220
Mendy Bennett
Experienced with Ad network & Ad servers.
Mobile | Ad Networks and 1 more
View Profile
User photo
3060
Karen Fitzgerald
7 years in Cross-Platform development.
Mobile | Cross Platform Frameworks
View Profile
Show All
X

Compare Products

Select up to three two products to compare by clicking on the compare icon () of each product.

{{compareToolModel.Error}}

Now comparing:

{{product.ProductName | createSubstring:25}} X
Compare Now