Web Development With Python
Before moving forward with Django, it is important to ask ourselves what the role of Python in general is in this whole scheme that we have just introduced. When developing desktop applications (for example, using the tkinter
standard module), you would usually design the graphical user interface (GUI, UI, or just "interface" for short) using Python functions and bind events that occur in the window (for example, a button press) to your own defined functions. This imples that both the graphical part and the logical part of a desktop application are developed with the same programming language and the same libraries.
In web development, it is more or less a general rule that the graphical part of a web application should be developed using the following three technologies:
- The HyperText Markup Language (HTML), to describe the layout of the UI;
- The CSS styling language, to add some styles (colors, shapes, borders, etc.) to the UI;
- The JavaScript programming language, to execute code in the web browser that can make changes to the UI.
Source files written in these three languages will be stored on the server, but will get interpreted or executed once received by the client. That is, all web browsers include HTML, CSS and JavaScript interpreters that are involved in the process of transforming the server response into the neat websites you visit every day. Using Firefox's “View Page Source" option (other browsers have similar options) in the context menu you can see the very content of the server response.
In the beginnings of the web, and currently in websites that do not require much user interaction, the URL address to which a request is made included the name of the HTML file whose content you want to return. For example, the https://example.com/contact.html
URL is indicating that you want to get the content of the contact.html
file that is hosted wherever the example.com
domain points to. In this hosting, a server program is running (such as Apache, NGINX, IIS, etc.) which receives requests from web browsers, reads the content of the file that was requested in the URL and returns it as a response to the browser. When you visit, say, https://example.com
, the web server usually returns the contents of the index.html
file by default.
Now, suppose that you need to develop a site for a company that offers programming courses, and this site should have a courses section where a list of available courses will be displayed with their respective start dates. If we were still in the 1990s, you would have to create a courses.html
file that is accessible via https://example.com/courses.html
, and the site administrator would have to manually update the contents of that file each time new courses or start dates are added or updated.
Over time, faced with the need to create dynamic websites whose content was not fixed in an HTML file on the server, but built on the fly each time a request was received, languages such as PHP, Perl, Java, and Python itself came into use in order to receive requests and construct an HTML response in real time. Thus, URLs like https://example.com/courses.py
began to appear.
When the web server received a request for a file ending with .py
(or .php
, .pl
, etc.), instead of returning its content, it was executed with the corresponding interpreter, and what was sent as a response to the client (= the web browser) was the output of the executed script (that is, in a Python script, anything sent to the standard output using print()
). So, this courses.py
script could contain something like this:
import sqlite3
print("<html>")
print("<title>Courses List</title>")
conn = sqlite3.connect("courses.db")
cursor = conn.cursor()
courses = cursor.execute("SELECT name FROM courses")
print("<ul>")
for (name,) in courses:
print(f"<li>{name}</li>")
print("</ul>")
print("</html>")
conn.close()
If the Python, Java, and PHP courses were loaded in the database, the output of this script would be:
<html>
<title>Courses List</title>
<ul>
<li>Python</li>
<li>Java</li>
<li>PHP</li>
</ul>
</html>
This is actually what would be sent to the web browser, which would interpret and display it like this:
This allowed people to create websites with dynamic content generated on each request in a very efficient way. Unfortunately, as web applications began to become more complex during the first decade of the 21st century, associating URLs with an executable file became very limited architecture. In this context, many Python packages for web development, known in the jargon as web frameworks, come into the picture, which were born with the aim of overcoming the limitations of the old method. Django is one of these packages, the first version of which was released in 2005.
As we just said, the web server, upon receiving a request, used to execute a certain script and return its output to the web browser. The dialogue between the web server and the executed scripts was carried out according to the rules of the CGI protocol. With the advent of Python web frameworks, a new protocol called WSGI was developed for communication between a web server and a Python application. While in CGI a URL is associated with an executable file, in WSGI URLs are usually bound to Python functions. This means that when the web browser makes a request to a URL, the server in turn sends that request to a function of a Python application, which itself returns a response to the server, and finally the server sends the response back to the client. Let's summarize this process in the following diagram:
In other words, the server passes control of the request to your Python and Django application so that it generates a response that will be sent to the client. As long as you return a response, you can run any Python code in your application, such as executing database queries or loading data from disk.
Something to be highlighted before moving on to the next section is that the process illustrated in the previous diagram occurs entirely on the website's hosting. That is why all database queries, for instance, are made from the Python application and not via JavaScript. The user will never be able to access the Python code from the “View Page Source" option abovementioned since that information is never sent to the client, only the response generated by such a code is sent. So, adding the possible interaction with the database and making the distinction of which processes are executed in the web browser and which others in the hosting, let's expand our diagram: