Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining views and urls in Django. Why aren't parenthesis used to call the function?

I have been going through "Python Crash Course", and I'm working on the "Django Web Application project (Learning Log)" stage. There is something that contradicts what I have already learned...

"""views.py file"""

from django.shortcuts import render

def index(request):
    """The home page for Learning Log."""
    return render(request, "learning_logs/index.html")

"""urls.py file"""

from django.urls import path

from . import views

app_name = "learning_logs"
urlpatterns = [
    # Home page
    path("", views.index, name="index")
]

In the code above, in "urls.py" file, views.index is called but without parentheses. Why is that?

Also, the index function has "(request)" parameter, but the argument is never provided. Am I missing something?

Note that this code works fine.

like image 429
Marcin22 Avatar asked Mar 03 '23 14:03

Marcin22


2 Answers

Because if you call the function, you will call the function when you load the file, and this will then produce a TypeError, since there is a missing parameter (request).

You here do not call the index view, you pass a reference to that view. That means that Django stores a reference to the function, and when a request is made, it will call the function.

In Python, just like many other languages, functions are "first class citizens". You can pass these as parameters, return these as results, etc.

For example we can define a function like:

def two():
    return 2

def sum_twice(f):
    return f() + f()

If we then call sum_twice(two) we thus pass a reference to the two function as f parameter in sum_twice. This will call f twice and sums up the result. Here it will thus return 4. If we would have called it with sum_twice(two()), then f would be 2, and f() thus would not work (and raise an error).

like image 166
Willem Van Onsem Avatar answered Apr 27 '23 11:04

Willem Van Onsem


A web application - or indeed any web server - basically does only one thing (although it can, and often does, do it in very complicated ways). A server listens for requests from a client (typically a web browser, when a user clicks a link, or submits a form) and then sends a response back to the client (in the case of a browser this will typically be an HTML document which is then displayed to the user, but it can also be many other things, including JSON, or other files like CSS, JS and image files which the browser will request if included in an HTML document, which are also needed for the page to function as intended).

So what any web framework needs to do, whatever language it's written in, is convert a request into a response. That is what any framework you care to mention, in any language, indeed does. And it's very natural to model that as a function, which takes the request (or rather a language construct which represents it) as input and returns the response as output.

And that is exactly what Django does. When the client makes a request to your Django application, what essentially happens at a high level is that this is request is converted to a Python object, and passed to one of your view functions, as its first parameter - the one which is conventially, and for obvious reasons of readability, called request. That function will return an HttpResponse object, which represents the response - which you don't usually have to construct yourself, there are some convenience functions which generate the right response for you when provided with other information, notably render and redirect.

And the URLconf is how you tell Django which function to invoke - that is, which function shall process the request in order to return the response to the client. It is a mapping of URLs to view functions - the first parameter to each path call is the pattern (or more generally a set of patterns, from which you can extract variables which are also passed to the view function), while the second is the function to invoke. (The third can be ignored for this purpose.) As Willem explains in his answer, this is not the same as calling the function, you are simply passing a so-called "reference" to the function - a Python object - to path. You are telling Django "when a request is made to this URL, call this function with the appropriate request object". But you are not calling it at that point.

like image 22
Robin Zigmond Avatar answered Apr 27 '23 11:04

Robin Zigmond