back to all posts

Setting up a basic Django project with Poetry

In this tutorial, we will go through the process of setting up the most basic Django project that we will be using for other posts and tutorials.

We will be using Pyenv and Poetry to manage the virtual environment and dependencies for your project.

Unfortunately, some things that I'm going through don't work exactly the same for Windows users (e.g. Pyenv). So, if you are following on a Windows machine you might run into some issues. If you do, try messaging me on Twitter, I'll try to do my best to help you.

During this tutorial, it might seem like too many things are going on things are becoming confusing. I'll try to separate it into manageable chunks that are easy to understand. And don't worry, some of the things in this tutorial only have to be done once.

The method of setting up repos that I propose can differ from others, but I really enjoy it. It helps me keep all the versions and virtual environments neat and tidy, which reduces the amount errors and bugs in the future. And if you stay with me till the end of the tutorial, hopefully, I can convert you to a Poetry person too :).

So, let's get the party started.

Prerequisites

Pyenv

  • We are going to use brew to install Pyenv. If you don't have brew installed on your Mac, run the following command:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  • now let's install pyenv:
brew update
brew install pyenv
  • If this didn't work for you try these fixes.
  • If you are on a Windows machine, follow the following instruction to install pyenv.

  • to test if this was installed correctly try running this in your terminal:

pyenv versions
  • we are going to be using Python version 3.9.9 in our tutorial, so let's get that installed with the following command:
pyenv install 3.9.9

Your terminal will start giving you some outputs. Wait for a minute or two until the download and installation are complete. This is everything we are going to cover regarding pyenv, we don't need to know more for the purposes of this tutorial.

Poetry

If you have Poetry installed you can skip this step.

So, let's first install Poetry. You can do that by running the following command in your terminal:

curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -

If you are on Windows you would run the following in your Powershell:

(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python -

The good news is that you have to do it once. To test that everything went smoothly, try running the following in your terminal:

poetry --version

Setting up the Environment

Alright, we are now ready to start. Here is what you want to do:

  • Open up your terminal, cd into the directory that you use to store all your code. For me it is:
cd ~/code
  • Then create a new directory for your project. I'm going to call mine "basic_django", but you can call it whatever else you want:
mkdir basic_django && cd basic_django
  • Now, I suggest you open up your VS Code and open your newly-created directory. Alternatively, you can run this command in your terminal:
code .
  • Let's use pyenv to explicitly say what Python version we will be using in that repo. For that, run the following in your terminal:
pyenv local 3.9.9

You should see a file named .python-version created in your folder. That's good.

  • Now were are going to initialize Poetry project with:
poetry init
  • You will be prompted to confirm a couple of settings. You can just skip the following:
Package name [basic_django]:
Version [0.1.0]:
Description []:
Author [Rasul Kireev <rasul.kireev@guycarp.com>, n to skip]:
License []:
  • When you get to the following line type in "^3.8" and press Enter:
Compatible Python versions [^3.7]: ^3.9

The reason we do that is that the latest Django version requires the use of Python Version 3.8 and up.

  • When you get to these prompts, type in "no". We are going to add our own dependencies later on:
Would you like to define your main dependencies interactively? (yes/no) [yes]

Would you like to define your development dependencies interactively? (yes/no) [yes]
  • In the end, you would have gone through the process that looked something like this:
This command will guide you through creating your pyproject.toml config.

Package name [basic_django]:
Version [0.1.0]:
Description []:
Author [Rasul Kireev <rasul.kireev@guycarp.com>, n to skip]:
License []:
Compatible Python versions [^3.7]: ^3.9

Would you like to define your main dependencies interactively? (yes/no) [yes] no
Would you like to define your development dependencies interactively? (yes/no) [yes] no
Generated file

[tool.poetry]
name = "basic_django"
version = "0.1.0"
description = ""
authors = ["Rasul Kireev <rasul.kireev@guycarp.com>"]

[tool.poetry.dependencies]
python = "^3.7"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"


Do you confirm generation? (yes/no) [yes]
  • Now let's add the Django dependency and try running the test server. So, to add a dependency in a Poetry project you just simply do:
poetry add Django
  • After this command finished running let's see what we have. You should see two files:
    • pyproject.toml
    • poetry.lock

poetry.lock is a file that keeps all the project dependencies nice and constant so that if other people want to use your project, they will be able to install the exact same versions.

pyproject.toml is a nice visual file that lists all the project dependencies. In future posts, we will be using it to give our project configurations. Here is what we have in the pyproject.toml file right now (you should see something very similar):

[tool.poetry]
name = "basic_django"
version = "0.1.0"
description = ""
authors = ["Rasul Kireev <rasul.kireev@guycarp.com>"]

[tool.poetry.dependencies]
python = "^3.9"
Django = "^4.0.1"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

You can see that we are using the latest Django version, 4.0.1. If you want to use some other Django version, you can specify that when adding that dependency, like so:

poetry add "Django>=3.2.4"

If you want to change the version of the file retroactively, you can manually change the value in the pyproject.toml file and run:

poetry update
  • Let's initiate a Django project with the Django admin command:
poetry run django-admin.py startproject basic_django .
  • Ok, if you have never used poetry before this is important. In the command above can see I'm using poetry run. I'm adding this so that poetry runs the django-admin command for me from the virtual environment that will have all the dependencies that we specified earlier. If you don't want to keep typing poetry run for every command, you can simply run:
poetry shell

and then use commands as you usually would. However, I don't recommend that, since if you have multiple projects open, virtual environments might not work nicely with each other. I suggest explicitly running python commands with poetry run ….

  • Second thing to note is the "." at the end of the command. This tells us that we have a parent directory already created, no need to do that for us.

  • Now in your File Explorer you should have the following:

basic_django/ (This will be different for you)
manage.py      
poetry.lock    
pyproject.toml
  • Finally to test that everything is set up as it should be let's run the local server:
poetry run python manage.py runserver

Tip: you should not be writing these commands all the time. If you have already run one of these commands previously you can press the ⬆️ key on your keyboard, while in the terminal and it will show the previous command you run, so that you don't have to write it down again.

Another tip: This is related. If you start typing "poetry run" in your terminal and then start pressing the ⬆️ key, your terminal will show only commands that have started with these keywords.

You will see something like this:

Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
January 27, 2022 - 17:25:15
Django version 4.0.1, using settings 'basic_django.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

This is good! We can go to our browser and go to the URL specified in the output (http://127.0.0.1:8000/)

  • You should see a Django welcome screen.
  • Notice the following line in the terminal output: "You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions." This is because we haven't run any migrations, and that's by design. We will not run any migrations until we have created a custom user model. If you don't anticipate your app to have a user, then don't worry about this.
  • I did not yet write a guide on how to create a Custom User Model, so will refer you to the best resource I know and that is Will Vincent's blog

Adding Static Pages

Before we create models, databases, and other fun stuff let's first create some static pages. For that, we are going to create a "pages" application. I got this approach from Will Vincent, and have been using it for a long time.

  • Create a new application with the following command:
poetry run python manage.py startapp pages

You should see a new folder pop up in your Code Editor named "pages" 👍.

  • Head over to the urls.py file in the basic_django directory (remember for you the name of the "core" directory is different, whatever you chose when setting up the project) and add the following:
# basic_django/urls.py
from django.contrib import admin
from django.urls import path, include # new

urlpatterns = [
    path('admin/', admin.site.urls),
    path("", include("pages.urls")), # new
]

What we are doing here is we are adding a namespace to our site, basically saying that all the pages that will be created under the pages app will be at the root of the URL.

  • Head over to the setting.py in the root folder (basic_django for me) and search for the TEMPLATES variable and replace the DIRS list to be this:
# basic_django/settings.py
...
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [str(BASE_DIR.joinpath('templates'))], # new
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
...

This will tell our Django application that all templates are under the templates folder.

  • Now, let's actually create the templates directory in the root folder. You can do that in the VS Code UI, or with the mkdir command. Just make sure that you are in the root folder.
  • Inside the templates folder create a base.html file. Inside that html file add the following:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Basic Django Project</title>
</head>
<body>

  {% block content %}
  {% endblock %}

</body>
</html>

This template will be used as a base for all other templates in our project. Here, we can add the header, footer, and other components that will be present on each page of the site.

  • Now, let's create a template for the home page. Create a pages folder, under templates folder. And inside that folder create a home.html file and add the following to it:
{% extends 'base.html' %}

{% block content %}
  <h1>Helllloooooo!</h1>
{% endblock content %}

Here were are extending the base template and adding a header to it.

Tip: If you are doing this for the first time, this might seem like a hard, long, and annoying task. But once you get the hang of it, things become to make sense and fall into their places.

Now the last two pieces to finish the proper setup of our Django project are URLs and Views.

  • Let's start with views. Go to the views.py file under the pages folder and add the following code:
# pages/views.py
from django.views.generic import TemplateView

class HomeView(TemplateView):
    template_name = "pages/home.html"
  • And let's create a URL for that HomeView. Create a urls.py in the pages folder and add the following:
# pages/urls.py
from django.urls import path

from .views import HomeView

urlpatterns = [
    path("", HomeView.as_view(), name="home"),
]
  • Now if you start the dev server with:
poetry run python manage.py runserver

you should see the word "Helllllooooo!".

Conclusion

Congratulations! You are done with the Django Project Setup. After all of this you should have a directory looking something like this:

.
├── basic_django
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-39.pyc
│   │   ├── settings.cpython-39.pyc
│   │   ├── urls.cpython-39.pyc
│   │   └── wsgi.cpython-39.pyc
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── db.sqlite3
├── manage.py
├── pages
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-39.pyc
│   │   ├── urls.cpython-39.pyc
│   │   └── views.cpython-39.pyc
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── poetry.lock
├── pyproject.toml
└── templates
    ├── base.html
    └── pages
        └── home.html

After finishing this tutorial you should know how to set up a Django Project with Poetry and Pyenv. In the future, I'm going to be writing a guide on how to integrate various tools into your Django Project, and having this neat setup will help a lot.

If you run into any issues or have any questions, feel free to message me on Twitter.

Comments

To comment on this project please signup or login .

  • zacharybutler

    zacharybutler - 1 year, 6 months ago

    Thank you for this! I am working through William Vincent’s Django for Beginners Book but I wanted to use Poetry instead venv. If you ever have the time, a walkthrough of how to deploy a Django app that is being managed by poetry would just as helpful!

  • rasulkireev

    rasulkireev - 1 year, 6 months ago

    Hey Zachary, thanks for your comment. I've been working on a couple of improvements to how the site works and finished today.

    Now, I will focus on writing more guides. I will certainly cover deployment with poetry. But in short I use poetry only in dev. On every commit push I generate a new requirements.txt file (if something changed in the pyproject.toml dependencies and then install all the requirements in a venv on the server.

  • feedmittens

    feedmittens - 1 year, 2 months ago

    Hi - I'm not sure if it's a typo or my environment but in the line: "poetry run django-admin.py startproject basic_django ." I get a 'Command not found: django-admin.py', but leaving off the .py extension makes it run just fine. The command that worked for me is: "poetry run django-admin startproject basic_django ."