Chapter 1: Setting up the Virtual Environment
A good programmer is not afraid of technology because their confidence doesn’t lie in the programming language, but in their own skills and experience. Tools only make them more productive. We can’t build even the simplest website in an acceptable amount of time without the right software. Building websites with Python is possible on any modern operating system, regardless of the hardware behind it. The core team that maintains this fantastic language already takes care of some of the more tedious tasks, such as compiling it and optimizing it for the processor you’re using.
However, building a web application in Python, even if we only respond with plain text, requires a great deal of knowledge, including of servers and web applications as well as the WSGI or ASGI interface. We need to abstract that complexity to respond to requests, environments, asynchrony, WebSocket, database connections, and the other elements that define a current web application. That’s why we’re going to set up a desktop with everything you need to be a productive modern Django developer. We will build different real-time applications using the technology offered by Channels, a Django extension (developed by the same Django team), which includes a WebSocket server and WebSocket integrations. The architecture of the applications will differ from how server-side rendering works. The communication path between the server and the client will be bidirectional, allowing us to use it to receive or send events and/or HTML. My intention is that upon finishing the chapter, your focus will be on the code and not on complex configurations that may distract you. To achieve this, we will make use of Docker, the famous container manager, which will open up the possibility of adding all kinds of software already precooked to launch without investing practically any time: databases, web servers, mail servers, and caches, among others. Don’t worry if you have no experience with Docker. I’ll teach you the basics without going into low-level details. After a few tweaks, you’ll practically forget that it’s running in the background.
It’s important not only that we know how to write Python and create real-time infrastructures with Django but also that we have the skills to be independent of the operating system when deploying or working in a team. By virtualizing (or isolating) the processes, we can remain unconcerned about the operating system where it runs, making the project easy to continue for any specialist, and we can anticipate future problems that may occur when deploying to a production server.
In this chapter, we’ll be covering the following topics:
- Exploring the software required
- Adding dependencies
- Configuring the IDE
- Installing Django
- Creating our project
Exploring the software required
In this section, we will take a look at the software that we’ll be using throughout the book and how to install it. The code for this chapter can be found at https://github.com/PacktPublishing/Building-SPAs-with-Django-and-HTML-Over-the-Wire/tree/main/chapter-1.
- Linux distribution, preferably Ubuntu or Debian
- macOS in its latest version
- Windows 10 or higher, preferably with the Linux subsystem active and Ubuntu or Debian installed
- BSD descendants, preferably FreeBSD
I assume that if you are reading this book, you already have experience with Python and you have an IDE or rich editor that is ready. If you need to change the IDE, I have recommended, from most to least highly recommended, in the following list some that I consider perfect for working with Python:
- PyCharm Professional: If you are a student at a recognized school, you can claim a free student license from JetBrains. Otherwise, I encourage you to pay for the license or use their demo. There is a free version of the IDE, PyCharm Community Edition, but you will not be able to use the Docker interpreter, as this is a feature of the Professional version. You can download this editor from https://www.jetbrains.com/pycharm/.
- Visual Studio Code (VSCode): This is a very popular editor in web development, created and maintained by Microsoft. You can download this editor from https://code.visualstudio.com/.
- Emacs: This is very easy to use with a preconfigured framework such as Spacemacs or Doom. You can download this editor from https://www.gnu.org/software/emacs/.
- Sublime Text with the Djaneiro package: This is the easiest option if you are not looking for complications. You can download this editor from https://www.sublimetext.com/.
Don’t force yourself to change. A code editor is a very personal thing, like choosing a brand of underwear: once you find one that fits your way of being, you don’t want to change. I understand that you may not feel like learning new shortcuts or workflows either. Otherwise, if you have no preference, you are free to visit the website of any of the preceding editors to download and install it on your computer.
All the examples, activities, and snippets in the book will work with whatever your editor or IDE of choice is. They will mainly help you with syntax errors, autocompletion, and hints, but your code will be self-contained since it is always stored in plain text. A Python programmer is a Python programmer in any editor but not all editors work well with Python.
You don’t need to install it. You’re reading correctly; the editor didn’t make a mistake in the review. We’ll use Docker to install a Python container capable of launching basic commands in Django, such as creating a project or an app or launching the development server.
I assume that if you are here, it is because you feel comfortable programming with Python. If not, I would recommend you read some of Packt’s books:
- Learn Python Programming – Third Edition, Fabrizio Romano and Heinrich Kruger, Packt Publishing (https://bit.ly/3yikXfg)
- Expert Python Programming – Fourth Edition, Michał Jaworski and Tarek Ziadé, Packt Publishing (https://bit.ly/3pUi9kZ)
In the case that you want to install it directly through the terminal, you will need to search for Docker Engine (https://docs.docker.com/engine/). This is highly recommended if you use Linux or BSD.
If you have no knowledge or relatively basic experience with it, I recommend looking at another of Packt’s books, such as Git Essentials – Second Edition, Ferdinando Santacroce, Packt Publishing (https://bit.ly/3rYVvKL).
POST, and the like) work as expected, watching the communication over WebSocket to make it smooth, and sporadically manipulating the rendered HTML.
WebSocket is a bidirectional communication protocol, different from HTTP, which facilitates the sending of data in real time between a server and a client, in our case, between a Django server and a frontend client.
In this book, I will use the Firefox Developer Edition (https://www.mozilla.org/en-US/firefox/developer/) browser because it is so convenient to manage the aspects mentioned using it. You are free to use any other browser, such as Chrome, Safari, or Edge, but I’m not sure whether all the features I will use are available with those browsers.
With the software installed, we can start working with the preparations around Python and Docker to run Django or future Python code.
We’re going to run Python via Docker and a configuration file. That way, any developer can replicate our code regardless of whether they have Python installed on their machine and they will be able to run the associated services with just one command.
First, we will create a Python file called
hello.py with the following content:
print(“Wow, I have run in a Docker container!”)
The code is ready. We can continue.
The goal will be to configure Docker to run the file. Sounds easy, doesn’t it? Here we go!
# Image FROM python:3.10 # Display the Python output through the terminal ENV PYTHONUNBUFFERED: 1 # Set work directory WORKDIR /usr/src/app # Add Python dependencies ## Update pip RUN pip install --upgrade pip ## Copy requirements COPY requirements.txt ./requirements.txt ## Install requirements RUN pip3 install -r requirements.txt
This file is used to create a Docker image, or template, with instructions that will be cached. Since they are precached, their launch will be almost instantaneous. Let’s check out what’s going on in the code:
FROM python:3.10, we are using another existing image as a base. We are extending the work already done. But... where is it? Docker has a repository full of images, or templates, called Docker Hub (https://hub.docker.com/), a place where developers selflessly upload their work. There is an official image called
pythonand we mark it with a tag to use version 3.10. If you have worked with Docker before, you might be wondering why we are not using the Alpine version, the famous operating system that saves so much space in servers around the world. For two reasons: Python is slower (https://pythonspeed.com/articles/alpine-docker-python/) and it doesn’t have the ability to compile dependencies. The Slim version also exacerbates the last problem and is recommended only for production versions that are short of space.
ENV PYTHONUNBUFFERED: 1shows us the Python messages, for example, when we use
print(). If it was not added, they would go directly to the Docker log.
- By adding
WORKDIR /usr/src/app, we define the path in which the commands will be executed inside the Docker container, not inside our operating system. This is equivalent to changing the directory with
- We will also take the opportunity to install the Python dependencies that we will be adding in the future inside
requirements.txt. We update pip with
RUN pip install --upgrade pip, copy the list of dependencies from the folder to the image with
COPY requirements.txt ./requirements. Txt, and finally, run pip to install everything with
RUN pip3 install -r requirements.txt.
- At the root of the project, we create another file called
docker-compose.yamlwith the following content:
version: '3.8' services: python: build: context: ./ dockerfile: ./Dockerfile entrypoint: python3 hello.py volumes: - .:/usr/src/app/
This is the orchestrator, a file where we define each service and its configurations. In this case, we are only going to have a service called
build, we tell Docker to use the image that we just defined in the
entrypoint, we indicate what it should do when the service is launched:
python3 hello.py. Finally, in
volumes, we tell it to mount the root directory, represented by a single dot, with
/usr/src/app/, which is an internal directory of the image. This way, the service will have access to all the files in the folder.
- Next, we create an empty file called
requirements.txt. We will not add a single line, though the file must be present.
We’re ready to go! Open the terminal, go to the working folder, and tell
docker-compose to pull up the services:
cd [your folder] docker-compose up
Docker will gradually perform several tasks: it will download the base
python image, build its own image by executing the instructions we have defined, and raise the
python service. It will print 2 lines per console, as in the following:
python_1 | Wow, I have run in a Docker container! python_1 exited with code 0
We’ve executed the Python file! Victory!
With the recent ability to run Python using Docker, it’s time to integrate it into an IDE to make it easier to run without using the terminal.
Configuring the IDE
PyCharm is highly popular because it’s a tool specially prepared to work with Python and it also includes interesting integrations with databases, Git, HTTP clients, environments, and the like. One of the most used is certainly the one related to Docker, so I will use this fantastic IDE in future examples. However, as I said before, it is not mandatory to use it; there are enough alternatives to please everyone. All code and activities shown in this chapter will work independently of the editor.
To set up the IDE, follow these steps:
- Open the folder where you want to work using PyCharm (File | Open). A directory tree will be displayed on the left.
- Click on the Python file (
hello.py). It’s not possible to run the Python code if you don’t use the terminal; PyCharm doesn’t know where the Python interpreter, or executable, is otherwise. It’s inside a Docker image that the operating system can’t access, for now.
Figure 1.1 – Open the Python file
- PyCharm may open a popup that suggests creating a virtual environment. You can skip this step or close the window; we will use Docker for the job. If you don’t see the window, you can continue without fear.
- We then check whether we have the Docker plugin installed. Go to File | Settings | Plugins and look for Docker.
- If it is installed, it will appear in the Installed tab. If not, you will have to look for it in Marketplace and then click on the Install button. Then, restart PyCharm. Ensure you do this. Otherwise, we won’t be able to continue.
Figure 1.2 – Installing the Docker plugin
- Now open File | Settings | Build, Execution, Deployment | Docker and press the + button. Then, search for Docker.
Figure 1.3 – Connecting with Docker
Dockerin the Name field, for example, and activate Unix socket. At the bottom, you will see the Connection successful message.
- We only need to tell PyCharm not to look for the Python interpreter, or executable, on the machine (if there is one) and to use the Docker service we have created instead.
- Go to File | Settings | Project: Executable Python. Here, we deploy the Python Interpreter, select Remote Python xxx Docker Compose, and click on Apply. The interpreter name may change depending on the folder name.
Figure 1.4 – Adding the Python interpreter
- It will automatically detect the dependencies that are already installed on the machine but we will ignore them. By the way, this is a good place to manage all Python dependencies visually.
- Now, it’s time to run the Python code using the configuration you just made.
- Close Settings and focus on the directory tree (on the left side). Right-click on
hello.pyand then Run ‘hello’.
Figure 1.5 – Running Python with PyCharm
- At the bottom of the editor, an area with the log of the execution will open. As proof that it has been done successfully, we can see the
Figure 1.6 – Viewing the Python execution log through Docker integration
Figure 1.7 – Launching containers through Docker integration
- On line 5 in Figure 1.7, you can see a green arrow; when you click on it, it will launch the service and, again, the Python code.
PyCharm is already integrated with Docker and is able to launch Python with its dependencies in isolation from the operating system. We are ready to work directly with Django. We are going to create a simple project using the official Django client to have a minimal structure when developing.
We will add the following content to
requirements.txt, which is currently empty:
# Django django===4.0 # Django Server daphne===3.0.2 asgiref===3.4.1 # Manipulate images Pillow===8.2.0 # Kit utilities django-extensions===3.1.3 # PostgreSQL driver psycopg2===2.9.1 # Django Channels channels===3.0.4 # Redis Layer channels_redis===3.2.0
- Django: This automates many important tasks, such as database connections, migrations, HTML rendering, sessions, and forms. In addition, being one of the most used and active frameworks, it gives us a high degree of security.
- Daphne: An asynchronous server maintained by the Django team itself. We’ll need it to work with WebSocket, to emit or receive data without blocking the app.
- asgiref: An ASGI library that needs Channels to work.
- Pillow: The mandatory Django library for manipulating images.
- django-extensions: A set of extensions that adds elements, such as jobs, script execution, database synchronization, and static storage in S3.
- Psycopg2: The driver to connect to PostgreSQL, the database that we will use and is most recommended to use with Django.
- Channels: Adds protocols and functionality for working with WebSocket to the heart of Django.
- channels_redis: We must have a record of the connections that we have active and the groups to which they belong. Using a database that writes to the hard disk is an inefficient way to manage it. To solve this, we’ll connect with a Redis service later, as it works on volatile memory and is incredibly fast.
Figure 1.8 – PyCharm asking whether you want to install the new dependencies
Figure 1.9 – PyCharm asking whether you want to install the requirements plugin
Figure 1.10 – Color codes thanks to the plugin
With PyCharm, this can be done in a visual way. Go to Dockerfile, right-click on the double arrow shown in the following screenshot, and select Build Image for ‘Dockerfile’:
Figure 1.11 – Compiling a Dockerfile image using PyCharm
By recreating the image, we’ve integrated all the dependencies inside the image; now, Django has everything we need. To check that it’s installed and we have version 4, we’ll temporarily modify
Entrypoint: django-admin --version
And then, we’ll run the service.
Remember that you can do this by clicking on the green arrow next to Python (line 5 in Figure 1.12) or through
Figure 1.12 – Checking which version of Django is installed
All this work can serve as a template for future Python developments. Don’t lose it!
After creating a minimal template through the Django client, we’re going to configure it to launch the test server every time the service is up.
Creating our project
Django needs its own directory and file structure to work. That’s why we need to generate a project via
django-admin, a terminal client built to launch Django tasks. Don’t worry! You don’t have to install anything new; it was added when we added the Django dependency.
# Create the 'hello-word' project django-admin startproject hello_world # Create a folder to host the future App with the name 'simple-app'. mkdir -p app/simple_app # Create the 'simple-app' App django-admin startapp simple_app app/simple_app
Here is what we are doing:
- With the first instruction,
django-admin startproject hello_world ., we’re creating a project (
hello_worldand, with the final dot, we’re telling it to make it in the directory where we’re running it.
- When we launch
mkdir -p app/simple_app, we create a directory called
simple_appwhich is inside app. The goal is to organize the apps, saving them all in the same directory; we also create the folder in which the first app will be saved:
- Finally, we create the app with
django-admin startapp simple_app app/simple_app. The
app/simple_appparameters define the app’s name and its location, respectively, which we created with the previous command.
- In short, we’ll call the project
hello_world, and inside it, we’ll have a single app with the original name
PyCharm may suggest that you install a plugin to check for syntax problems; it’s a good idea to do so.
Figure 1.13 – PyCharm suggests installing a syntax checker for shell files
version: '3.8' services: python: build: context: ./ dockerfile: ./Dockerfile entrypoint: bash start-project.sh volumes: - .:/usr/src/app/
We launch the container as we have already learned to: open the
docker-compose.yaml file and click on the double green arrow in
services or the single arrow in
If you are using the terminal or another editor, we will use
docker-compose in the directory:
When Docker finishes, the new files and directories will appear. Be patient if you don’t see them in PyCharm; sometimes it has a hard time refreshing when new files appear. You can wait or right-click on any file and click Reload from Disk.
Figure 1.14 – The newly generated Django project
Modify it by adding the following:
python3 manage.py runserver 0.0.0.0.0:8000
If you haven’t worked with Django before,
manage.py is equivalent to using
django-admin. The advantage of the former is that it uses the project’s configuration, while
django-admin is more general and you have to tell it where the configuration is; so, it’s more practical to use
manage.py as soon as the project exists.
The action we want to launch is to raise a development server with
0.0.0.0.0:8000 parameter indicates that we are open to any IP that makes the request and finally, we will use port
8000 to accept connections.
Altogether, it will look like this:
version: '3.8' services: python: build: context: ./ dockerfile: ./Dockerfile entrypoint: python3 manage.py runserver 0.0.0.0:8000 ports: - “8000:8000” volumes: - .:/usr/src/app/
We launch the service again. Now, open your favorite browser and enter
127.0.0.1:8000. You’ll find the Django welcome web page.
Figure 1.15 – The Django default page
As a last detail, if you are using the terminal, you will find that the container never stops. That’s because the web server, as a good server, is constantly running and waiting for requests until we tell it otherwise. Press Ctrl + C if you want to close it. In PyCharm, you should click on the red Stop square.
Figure 1.16 – Stopping Docker services via PyCharm and its integration
We have just acquired the skills to configure and build a Python project using Docker containers. We started with the basics, creating an image that runs a Python script and also installs all the dependencies we declared in
requirements.txt. Then, we automated the creation of a Django project with a simple script and set up the development server.
On the other hand, to make container management easier, we have integrated an IDE into the flow, in our case, PyCharm. It gives us the possibility to launch some of the functionalities that we will use the most: building a custom image, executing a container composition (now we only have a service for Python), visualizing the log, and restarting and stopping containers. But let’s not forget that all these tasks are accessible from the terminal, using
In the next chapter, we will build a complete project in Django with various databases, a web server, and other tools that we will need to build a complete project. In addition, we will integrate Django’s configuration with Docker to facilitate its deployment with different configurations.