Processing requests in Django

Any web application exists to provide information to clients and receive it from them. A client sends a request to the server and it answers with some response. Generally, the communication between these different sides is processed by the HTTP protocol utilizing GET, POST, and some other kinds of requests.

How to process GET requests in Django

We assume that the name of the Django project is “factory” and the name of the application is “candies”.

Let’s look at the assortment:

candies = {
    "Fudge":  {
        "color": "beige",
        "price": "priceless",
        "available": 100,
    },
    "Chocolate shock": {
        "color": "brown",
        "price": "precious",
        "available": 50,
    },
    "Marshmallow" : {
        "color": "pink",
        "price": "all the money in the world",
        "available": 200,
    },
}

On the main page, Willy wants to put just the assortment list and that’s it. So when you go to his site, you send a GET request to his service. GET is a method used to receive data from the server.

Django has classes that assume control over routine work with HTTP requests, so the main part you should implement without anyone else is the response. The response is an instance of the inheritors of Django HttpResponseBase class, as HttpResponse. We add this piece of code to the candies/views.py module:

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

class MainPageView(View):
    def get(self, request, *args, **kwargs):
        html =  "\n".join(f"<div>{candy}</div>" for candy in candies)
        return HttpResponse(html)

First, we make a new class and inherit it from the View. To provide a method to deal with the GET request, we basically characterize a method with the name “get”. This is an overall rule in Django, so if you need to make a POST handler, you define a method with the name “post”, and so on.

In this way, back to our sweet matters: passing HTML as a string to the HttpResponse class, we return a basic HTML page with a list of candies. Django application does the rest of the work without anyone else to send the information to the client. It’s easy to make a response.

Not Found Pages

For every customer who wants to find out about a specific candy, we make another page and class to process that request. Furthermore, if the customer gets some data about a nonexistent candy, we must report that we were unable to find it. The corresponding HTTP status code is 404, yet we don’t perceive any codes in the previous example.

As we stated, Django does a great deal of work under the hood. The HttpResponse set status code 200 in the answer for you, which implies that the communication was OK. We can’t change this code in the HttpResponse class, yet we can utilize the Exception class Http404, which will signal to a user that they’re attempting to GET a page that doesn’t exist.

How about we make a handler for a custom candy page in the same module:

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

class CandyView(View):
    def get(self, request, candy_name, *args, **kwargs):
        if candy_name not in candies:
            raise Http404

        candy_info = "".join(
            f"<tr><td>{key}:</td><td>{value}</td></tr>"
            for key, value in candies[candy_name].items()
        )
        return HttpResponse(f"<table><tbody>{candy_info}</tbody></table>")

As you see, the third parameter in our GET method is cryptic “candy_name”. We will learn how to pass this positional parameter at the next step; for now, just assume that we get the name of the candy from a user’s request. If we have this sort of candy, we display all the information about it. But if we don’t have one, we raise Http404 Exception because we can’t find it in our stock.

Pay attention that we return an instance of HttpResponse and raise Http404 since Http404 is an exception class

URL Routing

We create handlers for requests, but how does Django choose the appropriate one? For this purpose, we define URL routes in factory/urls.py module:

from django.urls import path, re_path
from candies.views import MainPageView, CandyView

urlpatterns = [
    path("candies/", MainPageView.as_view()),
    re_path("candies/(?P<candy_name>[^/]*)/?", CandyView.as_view()),
]

For instance, if Willy’s site has the hostname www.willywonka.com, at that point the assortment page will be available at the address www.willywonka.com/candies, and data specifically about fudge will be found at www.willywonka.com/confections/Fudge.

In the subsequent path link, we see a regular expression (?P<candy_name>[^/]*). This expression extracts the variable candy_name from the link and passes it to the handler. That is the manner by which we get our candy_name in the previous example.

To tie a link with a suitable handler, we can call way or re_path functions and add the result to the URL patterns list. The first argument of each function receives a string that describes a pattern for a link that comes after the hostname. It very well may be a simple string in path function and a regular expression in case of re_path. The subsequent argument is a handler that will process a request.

The order of the links in URL patterns is kept when Django searches for the necessary handler. If you paste regular expression “candies/(?P<candy_name>[^/]*)/?” before “candies/”, you will never arrive at the second one since “candies/” is a subset of the first regular expression. So you should paste the superset expression latter on the list.

The path “” (empty string) is a superset for all routes. If you paste it first in the URL patterns list with call to re_path, the various handlers will become unreachable.

Conclusion

To process a request in the Django application, you should define a handler and implement all methods that it can process. If you inherit this class from the View, you should match the desired HTTP verb with the same method in your class. Specifically, if you want to process the GET request, you should define the “get” method and return an instance of the Django HttpResponse class.

After you do that, you can bind this handler to the link it belongs to. Just add it to the list of URL patterns at the urls.py module.

Now, let’s try to solve a problem

Now the client for your application is a user who wants to know what rating a particular film has. You only have several ratings, all of which are stored in the CINEMA_RATINGS dictionary. You should implement a handler for the GET requests.

If a film has a rating, you should return a HttpResponse with only a rating in it.

If there is no such film in your rating database, raise Http404 Exception.

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

CINEMA_RATINGS = {
    "The Dark Knight": 8.2,
    "The Shawshank Redemption": 8.3,
    "Pulp Fiction": 8.1,
}


class CinemaRatingView(View):
    def get(self, request, film, *args, **kwargs):
        if film not in CINEMA_RATINGS:
            raise Http404
        film_info = CINEMA_RATINGS[film]
        return HttpResponse(film_info)