How Django HttpResponse works in a Client-Server communication
Some modules or functions used commonly in Django must be daunting to understand, especially when you’re unfamiliar with the whole Django syntax thing.
For example, the HttpResponse() function used in Django views can be easily confused with other functions such as the render() function. However, in this article, I will uncover the ins and outs of the HttpResponse() function.
What is HttpReponse in Django?
Django HttpResponse is the response in the form of a page or data sent back to a user upon requesting a view by accessing a particular URL. To make a request to a view, in Django, a user accesses a particular URL, triggering a request to Django that passes through the URL route to the view associated with the URL. The view responds with a response, generally referred to as the HttpResponse.
Before we get into much detail, we must first understand how a client application such as a browser communicates with a server.
What is client-server communication, and how does it work?
Client-server communication is the exchange of data packets/information between the client and server components. A client component may involve a simple web browser such as Google Chrome. The client requests the server component by accessing any URL available on a server.
The server component includes the hosting resources that make your web application or websites available worldwide. The server is responsible for handling requests made by a client and providing a response.
The hosting service will set up a server for you whenever you purchase a web hosting plan, either for WordPress or a Custom-made website. The server will generally have a web server that handles the requests and an application server that handles business logic.
For a WordPress website, the web server will be Apache, and the application will be WordPress software. The web server may be NGINX for a custom-made Django website, while the application server would be Django.
More about how servers work here.
After the web server receives a request from a client, it forwards the request to the application server to manipulate the request and provide feedback to the web server. The web server then forwards the response to the client.
How does Django handle requests?
Django receives a request whenever the web server triggers access to a particular web page or resources on the Django web application. The request is made by a user accessing the URL of a page.
Django then connects the URL to a particular view that processes the request and returns a response through the URL. The response is then sent to the web server and then to the client application.
In a Django view, we can return many things to a user upon making a request, be it data from the database, a page, an HTML template, or a page.
Whatever it is that is sent back to the user; it is a HttpResponse. HttpResponse is a response sent through the HTTP protocol. The HTTP protocol is used for transmitting hypermedia documents such as HTML and data back to the client.
So, a client requests a page by accessing a particular URL on a website, the request is handled by the view, and the view responds with a response using the HTTP protocol.
For demonstration,
let’s create a new Django project that requires a user to provide two integer numbers upon accessing a particular URL, sends the numbers to a Django view for processing, and the view responds with a HttpResponse containing the result of the added numbers.
Open the Terminal and create a new Python virtual environment for the new Django project.
python -m venv ~/.virtualenvs/new_django_project_env
After creating the Python virtual environment, activate the environment and install Django.
source ~/.virtualenvs/new_django_project_env/bin/activate
pip install django==4.0
Create a new directory to store the new project files and navigate into the new folder.
mkdir ~/Desktop/newDjangoProject && cd ~/Desktop/newDjangoProject
Create a new Django project using the django-admin
command
django-admin startproject DjangoAddProject .
Open the new Django project directory using your preferred IDE or code editor. I will be using Visual Studio Code.
code .
Create a new file and name it views.py inside the project’s main directory – the directory that has the projects’ settings.py file.
touch DjangoAddProject/views.py
Open the views.py file with your code editor and type the following lines of code:
from django.http import HttpResponse
def add_view(request, integer1, integer2):
result = integer1 + integer2
return HttpResponse(str(result))
In the code above, we’re importing the HttpResponse into our view.
Then, we create the add_view view that must receive two integers as arguments from the URL making the request.
The add_view view takes the numbers supplied by the user in the URL and adds them.
Then, the view manipulates the numbers by adding them.
Then, here comes the use of HttpResponse — the HttpReponse takes the manipulated data, convert it into a string, and returns it to the user that made the request using the same URL.
Open the urls.py and replace it with the following lines that handle the URL configuration for our add_view view:
from django.contrib import admin
from django.urls import path
from .views import add_view
urlpatterns = [
path('admin/', admin.site.urls),
path('<int:integer1>/<int:integer2>', add_view),
]
We’re importing the add_view view through the from .views import add_view
line into the URL configuration file so that we can connect it to a URL.
The other new line, path('<int:integer1>/<int:integer2>', add_view),
, creates a new URL that requires a user to enter two numbers separated by /. Then, we instruct Django to take those two numbers and supply them into our view as arguments.
Supplying the two numbers to the view through the URL is referred to as the request.
The view will take these numbers, process them, and provide an HTTP response in the form of string data.
So, the process goes like this:
Make a request by accessing a URL —> request is sent to the view associated with that URL —> The view processes the data —> the view responds using the HttpResponse() function.
Therefore, when making a request to the local server by accessing the URL 127.0.0.1:8000/2/4, Django will take the integers 2 and 4 and check if they are integers as required in the URL path converter, <int:integerx>.
Django supplies the numbers to the add_view view if the numbers are integers. The add_view view adds 2 and 4 and gives back a response that contains the number 6.
To make it more clear to you, adjust your add_view function like this:
from django.http.response import HttpResponse
def add_view(request, integer1, integer2):
result = integer1 + integer2
data_to_return = f'{integer1} + {integer2} = {result}'
return HttpResponse(str(data_to_return))
Go back and supply different numbers, and you’ll see how Django works so that you grasp the concept of making requests and Django providing responses.
As I said, a view can return different data types to the user.
Not only can you return strings, but also images, forms, XML documents, or data from the database.
Here’s an example of a view that returns a whole HTML page but uses the render() function.
from django.shortcuts import render
def home_page(request):
template_name = 'index.html'
return render(request, template_name)
Instead of providing string data, the above home_page view will return a full HTML page and render it to the user.
The HTML page can contain data from the data, a Django form, custom CSS styling, JavaScript code, e.t.c. Rendering takes care of the CSS styling and JavaScript processing on the page.
That’s more of the HttpResponse.
But, what happens if a user accesses a page or makes a request to a page view that doesn’t exist on a whole Django project?
Or the client accesses an incorrect URL route. Say, for example, a deleted blog post or page.
The web application must return something, right?
The view always handles a request made to a URL. However, if the URL route doesn’t exist, there isn’t any view to handle the request.
The default response for a non-existing page is a 404 error page in Django.
However, you can implement a try…except functionality on a Django view to display a custom message to a user.
You may use the HttpResponseNotFound() function to return some response to the user instead of a generic 404 PageNotFound error. The web page returned may contain a message informing the user that the application did not find what they were looking for.
Let’s say we have a view that dynamically creates a category page from a list of categories. If a user makes a request for a category that doesn’t exist, you may alert the user that the category does not exist instead of the default 404 error page. If a category doesn’t exist, there shouldn’t be a page.
Let’s try to implement the use of blog categories in a Django blog application so that you may understand how the HttpReponseNotFound works.
Edit the views.py file and add the following Python dictionary object named blog_categories.
blog_categories = {
'general-programming': "General programming page",
'python-programming': 'Python programing page'
}
Use the Python dictionary object to create dynamic URLs and pages for each category.
def dynamic_categories_view(request, category):
try:
response = blog_categories[category]
return HttpResponse(response)
except:
result = f'No blog category page for category {category} was found!'
return HttpResponseNotFound(result)
Your final views.py file should look like this:
from django.http.response import HttpResponse, HttpResponseNotFound
blog_categories = {
'general-programming': "General programming page",
'python-programming': 'Python programing page'
}
def dynamic_categories_view(request, category):
try:
response = blog_categories[category]
return HttpResponse(response)
except:
result = f'No blog category page for category {category} was found!'
return HttpResponseNotFound(result)
What have we done there?
We’re creating a Python object that stores the URL route as the dictionary key and the message to display on a page as the dictionary value.
The URL route and the message will be created automatically instead of creating a view for each category.
In the Exception block, we check if a category that the user supplies when accessing a URL exists in the dictionary keys. If the supplied string matches a route in the dictionary key, Django automatically creates a page view with the response as the dictionary value.
On the other hand, if the user accesses a route that does not match any route in the dictionary keys, Django responds with a message indicating that the page doesn’t exist. Without the Exception block, Django would just throw a 404 PageNotFound error. But we don’t want that. We want a custom message indicating that the category does not exist.
Your final views.py file should look like this:
from django.shortcuts import render
from django.http.response import HttpResponse, HttpResponseNotFound
blog_categories = {
'general-programming': "General programming page",
'python-programming': 'Python programing page'
}
def dynamic_categories_view(request, category):
try:
response = blog_categories[category]
return HttpResponse(response)
except:
result = f'No blog category page for category {category} was found!'
return HttpResponseNotFound(result)
def add_view(request, integer1, integer2):
result = integer1 + integer2
returned_data = f'{integer1} + {integer2} = {result}'
return HttpResponse(str(returned_data))
Edit the urls.py file to add the new URL configuration for our dynamic category views.
from django.contrib import admin
from django.urls import path
from .views import add_view, dynamic_categories_view
urlpatterns = [
path('admin/', admin.site.urls),
# new line for dynamic categories
path('<str:category>/', dynamic_categories_view),
path('<int:integer1>/<int:integer2>', add_view),
]
Go ahead and try the categories view pages. Type 127.0.0.1:8000/python-programming or any URL route in the dictionary keys.
You should see a response indicating a valid page exists.
Otherwise, if you supply a non-existent category, Django will respond with a message informing you that the page does not exist yet for that particular category supplied in the URL.
That’s it for HttpResponseNotFound function. I hope you’re able to differentiate between the two.
What is the difference between HttpResponse and HttpResponseNotFound in Django?
The Django HttpResponse is a function that displays valid responses on a Django website. A view receives a request from a valid URL route, processes the requests, and responds to the client that requested the request through the HttpResponse function.
On the other hand, the HttpResponseNotFound function alerts the user of a non-existent page on a Django web application instead of displaying the default 404 page not found error.
And that’s it for this tutorial, and I hope you have learned more about Django and how a client application such as a browser and Django communicate together. Besides, learned how pages are created in a Django web application.
I hope to see you in the next tutorial.