Part 8 - Basics of Views and Routing in Django

November 28th, 2020 8 min read

This is part of the series Django For Beginners we are going to see about apps in app and we will see about models in django in this part.

In this post we are going to understand the idea of views and routing from scratch and see some types of responses and then we will learn about basic routing and to separate urls.py in separate files files.

what are views ?

Views are like middle man between request and response on your server they contain all you logic for a route, we will talk about route later in this post. They essentially process get the data needed for the request and process it and the return it as a response. This response can be of a variety of types, text, html , json , xml to name a few.

Now let’s see a example of a view,

from django.http import HttpResponse

def home_response(request):
    return HttpResponse("Hello World 😊.")

I tried to make is as basic as possible. What is happening above is when we receive a request and we call this view function it will return an simple text response, that is Hello World 😊. .

You may have noticed about request argument in the home_response view above it is compulsory argument it is a dictionary object and contains lot, by lot, I mean really a lot of information about the request of which most of the times you are not going to use directly. With request object we can access headers, user agent, ip, cookies to name a few.

In above example we returned text response but it is not what happens in real world, right 🤔 ? In real world scenarios we need to either prove a html response or a json or xml as a response. So let us see how to pass html as response for now.

from django.http import HttpResponse

def home_response(request):
    return HttpResponse("<h1>Hello World 😊.</h1>")

Returning HTML Pages in Response

I am lazy so I copied above code and just added <h1></h1> tags around our plane text response and wallah, it is now a html response but don’t you think it would be bad for long html responses with which we have to deal most of the times, so for that we keep html away from views all together so to keep code clean and follow the DRY principle . So you may ask where do we keep such code and the answer is we keep it in its separate folder to configure we just write 3 words in this huge mess of code which you don’t need to understand shown below,

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [ BASE_DIR / "templates" ], # HERE ARE THE MAGIC WORDS
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

We wrote BASE_DIR / "templates" what it essentially tells django is that to look for templates files , that is html files in base directory and then go to templates directory and it is not necessary that the templates directory must be called "templates but it is a convention that most of the developers follow.

Now let’s get back to views and see how to render templates from views,

say I have a html template, home.html and its path is templates/home.html .


<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0">
        <title>My Homepage</title>
    </head>
    <body>
    	<h1>My Homepage 😊.</h1>
    </body>
</html>

So to return it as a response we use render method from django.shortcuts as shown below,

from django.shortcuts import render

def home_page(request):
    return render(request, "home.html")

We just simply return template in a similar fashion as HttpResponse just instead of HttpResponse we return render method.

Syntax of render method is as follows,

render(request, template_name)

template_name should relative to the path of the templates directory. We can also pass data in dictionary format and we can display that data in templates let’s see it in an example,

from django.shortcuts import render

def home_page(request):
    context = {
        "grettings" : "My Homepage 😊.",
    }
    return render(request, "home.html", context)

and we can access this data in templates using double curly brace {{ variable_name }} . Let’s see how to do this,

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0">
        <title>My Homepage</title>
    </head>
    <body>
    	<h1>{{ grettings }}</h1>
    </body>
</html>

Note that I am not using context.grettings but I am using just grettings you can pass any valid data type in this dictionary and access it in template. Let’s say I have passed three items in the dictionary context, say obj1, obj2, obj3 with any valid data type, in our template we would have three variables obj1, obj2, obj3 with there respective values. Templating in django is a vast topics and deserves a post of its own.

JSON Response

We can also return json response in a similar fashion as HttpResponse. It can be seen below,

from django.http import JsonResponse

def my_json_response_view(request):
    JsonResponse({"response" : "My cool JSON Response 😎."})

URLS

Now after reading this you might be saying you told us how to send response but how and when to execute these responses, and how to use routes and your answer is here,

We define routes in urls.py in root of out project folder, and to do so we import views from our app in main and then assign each view to one or more urls,

from django.contrib import admin
from django.urls import path

# Changes
from myapp.views import home_page, about_page

urlpatterns = [
    path('admin/', admin.site.urls),

    # Changes
    path("", home_page, name="home"),
    path("about/", about_page, name="about"),

]

We assign route to views using path method and it has the following syntax

path(route_name, view, name)

Where route_name and view are compulsory and name if optional. We use name because it becomes easy to during redirect and stuff.

You may have noticed that in home route we have passed an empty string as route and it is because Django by it self adds / at the start of each route. So keep this in mind as it may cause you hours of headache to determine why you route is not working. Also add / at the end of each route as if you don’t add it it may cause you some problems and have definitely caused me many problems. Whenever a user visits let’s say to https:\\example.com\about-us and you have set route in your urls.py to /about-us/ then the user will automatically be redirected to https:\\example.com\about-us\.

Splitting Routes

But don’t you feel it has began to look messy and as we add more apps it will get out of hand and so for these reason we split our single view file and create multiple view file usually one for each app. It is also a good practice that keep code clean and readable. So to split our urls.py file we create urls.py in each app and then import path and create urlpatterns list , the name of the list should be same otherwise django will not detect URLs. You can use the following code snippet as your base template and copy and paste it.

from django.urls import path
from .views import home_page, about_page

urlpatterns = [
    path("", home_page, name="home"),
    path("about/", about_page, name="about"),
]

But we are not over here we need to tell to django to go to these file to obtain urlpatterns and we specify this using include method from django.urls and pass the relative path it as a string see example below,

from django.contrib import admin
from django.urls import path, include # Changes


urlpatterns = [
    path('admin/', admin.site.urls),

    # Changes
    path("", include("myapp.urls")),

]

We have also passed an empty string in place of route in above path method and this is because we don’t want any prefix with our urls present in urls.py in our app. So the route for the files in urls.py in myapp would be https:\\example.com\ for home and https:\\example.com\about\. We can also pass route if we like lets say instead of empty string I would have passed more\ the the routes will be a bit different and would be https:\\example.com\more\about\ and https:\\example.com\more\about\ respectively.

In next post we will see how to create dynamic urls and how to verify the type of data passed and so on. Guys if you like it please share because with your help we can reach to more people and I can continue to write with same joy and same excitement or more as I am writing right now.

Also check out some of my other posts down here.


You may also like: