In the gif above ☝️, keep an eye on how I can run py.test and django-admin without any extra settings, all read from my local env. By the way, I haven’t sped up the video, that’s how fast it all works 😁.

As a reference, here’s a sample project with everything discussed in this post: https://github.com/santiagobasulto/django-demo-project

And finally, this is the detail of packages and plugins used:

We have multiple Django projects in production. Some have been around for a long time, so they run on Python 3.6.9. The new ones are on Python 3.8.0. A single dev in our team must be able to work on all these projects. With pyenv, we can ensure that we’re all working in the same Python version. There’s a file .python-version that lists the version supported by the project. When a new dev starts working on the project, they can just do pyenv install and pyenv will take care of installing (and using) the correct Python version.

Poetry was a life changer. We used to have dependencies listed in requirements.txt files (with the usual solution of base.txt , dev.txt and prod.txt ). We’ve ran into some dependency conflicts and they were very hard to solve and keep correct.

If you’re not sure why Poetry is important, you should know that dependency resolution is a big deal in software. Poetry uses a deterministic algorithm to generate a “Lock File” and avoid Dependency Hell. Most major programming languages’ package managers have some sort of deterministic package resolution and lock files, including Java/Kotlin’s Gradle and Javascript’s npm. Read more about reproducible builds here. If you’re really interested in this topic, check out Nix.

When a new dev joins the project, they just need to do a poetry install and they’re good to go, ensuring their environment is the same as other dev’s and production.

Issues with Poetry

Before poetry, I was using virtualenv and virtualenvwrapper. I could set the PYTHONPATH and DJANGO_SETTINGS_MODULE environment variables in the postactivate file ( $PATH_TO_VIRTUALENV/bin/postactivate ) . So when the virtualenv was activated, I could just execute any django-admin command without the need of passing extra parameters.

With Poetry that wasn’t so simple. First, to “activate” the virtualenv created by poetry, you need to run the command poetry shell . And there’s no way to specify a script to run after the environment is activated, which meant there was no way to setup the Django environment variables. So I ended up running long commands like django-admin runserver --settings demo_project.settings.dev --pythonpath demo_project . This, of course, conflicts with my 3rd objective: a fast and dynamic environment. The solution was to include a few ohmyzsh plugins: poetry and autoenv.

With the Poetry plugin, when I cd into a Poetry based project, the virtualenv is automatically activated ( poetry shell ). With autoenv, I can define a file .in that contains the env variables to activate.