How I Set Up My New Mac for Django Development

Published on
Programmer sitting infront of their laptop, looking stressed

Background

The quick version: I wanted to move local development for an existing Django web app from one computer to another Mac computer - this is how I did it.

I built a Django web app several years ago (when I knew little about web development) and I've long held the idea to refactor its markup and styles to make it more modern, maintainable and reasonable.

The production version of the Django web app is constantly running inside a Digital Ocean droplet (basically a virtual machine that acts as a production server). I'm able to log into the droplet, either from my old computer or on their site's recovery console, run the virtual environment and then do various things like pulling changes from GitHub.

I recently bought a new Mac computer, and so I thought it would be a good time to try and move development of the web app from an older computer to this new one in order to attempt refactoring it. This blog post tries to outline what I did and why.

Replicating the production environment

With most web apps, the development flows from the local computer -> GitHub repo -> production environment. So, when you replace that local computer, you want to look towards your production environment and try to replicate it as much as possible.

I logged into the droplet (in the terminal on my old computer), ran the virtual environment, and then tried to establish two key things - the Python version running, and the packages installed.

$ ssh <admin_server_username>@<MY_DROPLET_IP_ADDRESS>

$ source ./venv/bin/activate

(venv) $ python --version
Python 3.8.10 # output

(venv) $ pip freeze
asgiref==3.5.2
backports.zoneinfo==0.2.1
certifi==2024.2.2
charset-normalizer==3.3.2
Django==3.2
...

I copied this list exactly and put it into a text file (running pip freeze > requirements.txt also does this for you automatically, but it gets stored in your production server). I would need it later when installing packages in my local environment.

pyenv

pyenv is simple tool that helps you choose what version of Python is used in a particular folder, which is exactly what I needed here. After installing it you have to update your shell configuration file, which is a script that runs every time you open a new session in the terminal. I use zsh, so I needed to follow the instructions here.

Here's a flow of what I did:

Installed pyenv via Homebrew:

brew install pyenv

I added some lines to my ~/.zshrc file:

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init - zsh)"' >> ~/.zshrc

I needed to reload the terminal or source the file to enact the config changes:

source ~/.zshrc

Then installed the Python version corresponding to the droplet version:

pyenv install 3.8.10

This writes a .python-version file that I guess sort of plants a flag saying 'Hey, here we only want to work with this version of Python here!', so when we later create a virtual environment, it make sure to do with this version of Python (you can check what Python versions you have available by running pyenv versions, where you should see your system version and the newly installed and available version).

Cloning the Django Project and Creating the Virtual Environment

The next stage was to clone the repo in my dev folder and then made sure to open the project root folder:

git clone git@github.com:<my-github-username>/<repo>.git
cd <repo>

Inside the project root, I then set the local Python version:

pyenv local 3.8.10

Next I created a virtual environment and activated it:

python -m venv venv
source ./venv/bin/activate

Inside this newly created environment, I checked which version of python is running inside of it:

python --version # output: Python 3.8.10

I used that file I created earlier of packages installed in the production environment, placed it in the project root, and ran a command that uses it to install packages in this new environment:

pip install -r requirements.txt

At this point we now have a virtual environment that matches the production server.

Creating the local database

My Django app uses PostgreSQL. Previously, I needed to download Postgres.app and pgAdmin before configuring things. But now it's pretty straightforward to get things set up from the terminal.

I installed PostgreSQL and then started a local database server

brew install postgresql
brew services start postgresql # run brew services stop postgresql to stop it

I then tried to create a superuser:

createuser -s $(whoami)

whoami is the token name for your macOS username. This caused an error because I think it automatically created a superuser using my macOS username when I installed postgresql, so I didn't need to create a new one? Anyway, next I need to create a local DB:

createdb my_local_db # name this whatever makes sense

Useful database stuff

To see a list of databases:

psql -l # press 'q' to exit

To connect to your db and open up a PostgreSQL shell:

psql my_local_db

And some useful commands to use when you're inside the shell (after the db is set-up):

\dt # lists all tables
\dn # lists all schemas
\conninfo # check the connection
\d books_book # this example describes the "books" table
\l # lists databases
\q # exit psql

Configuring Django app settings

In a Django project, there's an important configuration file called settings.py, where amongst other things we set up the connection to the database. At the end of this file in my project, I have this bit of code:

try:
from .local_settings import *
except ImportError:
pass

What this does is allow us a way to keep certain things secret (local_settings.py is added to the same folder that has settings.py, and it is added to my .gitignore file to make sure it doesn't get pushed to GitHub). So, I created this file and then added the database stuff to it:

DEBUG = True

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'my_local_db',
'USER': 'my_macos_username',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '',
}
}

SECRET_KEY = 'dev-secret-key' # in development, it doesn't matter what this is

No password is needed because of peer authentication - the default PostgreSQL configuration trusts local connections from the same system user without requiring a password.

Run the Django app locally

With the virtual environment running and in my project root, I then applied migrations (this sets up the tables in the database):

python manage.py migrate

Before running the development server:

python manage.py runserver

Visiting http://127.0.0.1:8000/, I could view the app, where it runs exactly like production.

Setting up SSH keys

The only thing left to do is set up SSH keys so that I can log into the droplet on my new computer. SSH is a protocol that allows you to log into and manage a remote computer or server using a command-line interface. We can generate SSH keys on any computer and then share our public keys to enable this protocol. The droplet already has the public SSH key for my old computer, and I needed to add a public SSH key for my new one to it.

I navigated these (slightly outdated) Digital Ocean guides to help:

First of all I use the ssh-keygen command-line tool to create a matched pair of cryptographic keys (a public key and a private key) on my Mac:

ssh-keygen

This created two files in my ~/.ssh folder:

id_ed25519 # private key - never share!
id_ed25519.pub # public key

I went into the .pub file and copied its entire contents, which looks something like this:

ssh-ed25519 BLAHBLAHBLAHBLAHBLAH <my_macos_username>@Mac

Then I logged into the droplet on my old computer, and opened the authorized_keys file:

$ nano ~/.ssh/authorized_keys

I pasted the copied SSH key at the end of the file, saved it and exited. After that, I needed to "set the permissions and ownership of the files" (I don't really understand what this means, but it's in the Digital Ocean guide):

chmod -R go= ~/.ssh
chown -R $USER:$USER ~/.ssh

After logging out of the droplet, and now in my new computer, I can test that the SSH stuff worked:

ssh <admin_server_username>@<MY_DROPLET_IP_ADDRESS>

It did, and now I can enter the droplet from my new computer without entering a password. Pretty cool.

Conclusion

This blog post has outlined how I moved local development of a Django app from one computer to a new Mac computer. It was a pretty hairy experience and not without a fair few stumbling blocks or course corrections (they aren't mentioned here to make things more streamlined and save me some embarassment!). But hopefully reading this guide will make things a little easier for you if you're in the same boar (or more likely just me when I need to do something similar in future). If you need to ask anything about this post send me a message and I'll be happy to get back to you!