> ## Content Index
> Fetch the complete content index at: https://honstain.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Django Service with Gunicorn
- URL: https://honstain.com/django-service-with-gunicorn/
- Published: 2024-03-16T15:18:50.000Z
- Updated: 2026-06-21T00:32:49.000Z
- Author: Anthony Honstain
- Tags: PostgreSQL, Django, Python, Gunicorn, IntelliJ

This will be a quick walkthrough of standing up basic Django with some fancy development tools like IntelliJ, mypy, and black. In addition to Django we will use DRF to implement a REST API and Gunicorn to expand on the basic Django runserver. 

This guide acts as a precursor, setting the stage for future posts where this Django service will be utilized as a dependency of the SQS consumer we created in this guide <https://honstain.com/asyncio-sqs-and-httpx/>.

**Why would you be interested in this write-up?**

- You're looking for some practical examples of setting Django with IntelliJ.
- You're interested in Gunicorn configurations for Django services.
  - This will give us some basic tooling to consider performance in future blog posts.

**What this post is not:**

- A replacement for the excellent Django tutorial [https://docs.djangoproject.com/en/5.0/intro/](https://docs.djangoproject.com/en/5.0/intro/?ref=honstain.com). We assume you have gone through the tutorial or can wing it.
- Security or CI/CD - we are primarily focused on getting a service setup for experimenting with development tools and eventually scaling/performance issue (subsequent posts).

💡

Source code for the django service discussed in this post: [https://github.com/AnthonyHonstain/django-user-service](https://github.com/AnthonyHonstain/django-user-service?ref=honstain.com)

## Overview of Key Dependencies 

The dependencies most relevant to this blog:

| Dependency                 | Notes                                                                                                                                                                                                                                                                        |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| gunicorn 21.2.0            | This is the thing subsequent posts will look at the most. [https://gunicorn.org/](https://gunicorn.org/?ref=honstain.com)                                                                                                                                                    |
| djangorestframework 3.14.0 | The only real logic we create for this service will be a DRF endpoint and a Django model. This version doesn't officially support Django 5 but I wanted to try it anyway. [https://www.django-rest-framework.org/#](https://www.django-rest-framework.org/?ref=honstain.com) |
| django 5.0.2               | Giving the new version 5 a test drive. [https://www.djangoproject.com/](https://www.djangoproject.com/?ref=honstain.com)                                                                                                                                                     |
| psycopg2-binary 2.9.9      | Needed for Postgres [https://github.com/psycopg/psycopg2](https://github.com/psycopg/psycopg2?ref=honstain.com)                                                                                                                                                              |
| postgres:16.2              | The PostgreSQL docker image [https://hub.docker.com/\_/postgres](https://hub.docker.com/%5F/postgres?ref=honstain.com)                                                                                                                                                       |
| black 24.2.0               | I have been getting a ton of value here, ymmv. I love that it consistently and with no effort on my part produces very readable and organized formatting. [https://black.readthedocs.io/en/stable/](https://black.readthedocs.io/en/stable/?ref=honstain.com)                |
| mypy 1.8.0                 | Static type checker - I still bump into odd things, but have found the juice worth the squeeze. [https://mypy.readthedocs.io/en/stable/](https://mypy.readthedocs.io/en/stable/?ref=honstain.com)                                                                            |
| poetry                     | Using poetry in place of pip, this feels more natural for production systems.                                                                                                                                                                                                |

# Setup The Django Service

The idea here is to take the source code and get it running locally.

## Get the Source Code

I have a public github repo you can pull or copy to get started.

[GitHub - AnthonyHonstain/django-user-service: An example Django 5.0 service with DRF, postgres, gunicorn.An example Django 5.0 service with DRF, postgres, gunicorn. - AnthonyHonstain/django-user-service![](https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg)GitHubAnthonyHonstain![](https://opengraph.githubassets.com/304d3737c475e70ab218dc0b17d559156e075deffc62be48b058de916231d6c9/AnthonyHonstain/django-user-service)](https://github.com/AnthonyHonstain/django-user-service?ref=honstain.com)

⚠️

This post does not contain enough information to take you through building a Django service from scratch. Please consider the Django tutorial if your looking for that sort of experience.

## Get Mamba or Decide on an Alternative

Similar to the previous [SQS consumer post](https://honstain.com/asyncio-sqs-and-httpx/) we are going to assume you are using mamba.

[Micromamba User Guide — documentation![](https://mamba.readthedocs.io/favicon.ico)document.write(\`<img src="../\_static/logo.png" class="logo\_\_image only-dark" alt="documentation - Home"/>\`);QuantStack & mamba contributors![](https://mamba.readthedocs.io/en/latest/_static/logo.png)](https://mamba.readthedocs.io/en/latest/user%5Fguide/micromamba.html?ref=honstain.com)

```bash
# CD into the project directory
mamba create -n django-user-service -c conda-forge  python=3.12
mamba activate django-user-service

```

## pyproject.toml and Poetry

We will be using poetry to manage the python dependencies for this service.

[Poetry - Python dependency management and packaging made easyPython dependency management and packaging made easy![](https://python-poetry.org/images/favicon-origami-32.png)Python dependency management and packaging made easy![](https://python-poetry.org/images/logo-origami.svg)](https://python-poetry.org/?ref=honstain.com)

This is the `pyproject.toml` for the repo [https://github.com/AnthonyHonstain/django-user-service/blob/main/pyproject.toml](https://github.com/AnthonyHonstain/django-user-service/blob/main/pyproject.toml?ref=honstain.com)

In the mamba environment you already have active:

```
pip install poetry
poetry install --no-root
```

## Django and mypy

I set this Django service up using mypy, there was one thing I missed that you might also want to be aware of. Its not enough to just add mypy and django-stubs.

The mypy configuration file: [https://github.com/AnthonyHonstain/django-user-service/blob/main/mypy.ini](https://github.com/AnthonyHonstain/django-user-service/blob/main/mypy.ini?ref=honstain.com)

![](https://honstain.com/content/images/2024/03/image-10.png)

Without the mypy configuration I ran into a number of mypy errors. 

**EXAMPLE ERRORS**

```
❯ mypy .
usercore/models.py:5: error: Need type annotation for "name"  [var-annotated]
usercore/models.py:6: error: Need type annotation for "age"  [var-annotated]
user_service/settings.py:30: error: Need type annotation for "ALLOWED_HOSTS" (hint: "ALLOWED_HOSTS: List[<type>] = ...")  [var-annotated]
Found 3 errors in 2 files (checked 15 source files)
```

We have the `django-stubs` dependency set, but we need to help mypy along with that mypy.ini file.

References:

[The mypy configuration file - mypy 1.9.0 documentation![](https://mypy.readthedocs.io/favicon.ico)mypy 1.9.0 documentation![](https://mypy.readthedocs.io/en/stable/_static/mypy_light.svg)](https://mypy.readthedocs.io/en/stable/config%5Ffile.html?ref=honstain.com#config-file)

[Integrating mypy into a Django project | Ralph MinderhoudRalph Minderhoud](https://www.ralphminderhoud.com/blog/django-mypy-check-runs/?ref=honstain.com)

[GitHub - typeddjango/django-stubs: PEP-484 stubs for DjangoPEP-484 stubs for Django. Contribute to typeddjango/django-stubs development by creating an account on GitHub.![](https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg)GitHubtypeddjango![](https://opengraph.githubassets.com/287f237780a1ff6a95af94a5287adf3d77e3405874f4b2d2b86c054183ff8e1d/typeddjango/django-stubs)](https://github.com/typeddjango/django-stubs?ref=honstain.com)

## IntelliJ and Django

I will provide some examples of configuring IntelliJ to work with Django, I didn't find it super intuitive and hope this could help others.

[IntelliJ IDEA – the Leading Java and Kotlin IDEIntelliJ IDEA is undoubtedly the top-choice IDE for software developers. It makes Java and Kotlin development a more productive and enjoyable experience.![](https://www.jetbrains.com/apple-touch-icon.png?r=1234)JetBrainsJetBrains![](https://resources.jetbrains.com/storage/products/intellij-idea/img/meta/preview.png)](https://www.jetbrains.com/idea/?ref=honstain.com)

You can skip this if you use an alternative editor.

![](https://honstain.com/content/images/2024/02/image-22.png)

### Django and Python Black

I also found python Black to play nice with Django and have included an example screenshot of enabling the Black formatted automatically in IntelliJ. This automated the majority of the formatting activities.

![](https://honstain.com/content/images/2024/02/image-20.png)

# Getting Django Running 

## Standing up the database

The core of this service is going to be a postgres database, which we will standup using docker compose.

`docker-compose.yml`

```yaml
version: '3.8'

services:
  db:
    image: postgres:16.2
    volumes:
      - postgres_data_product:/var/lib/postgresql/data/
    environment:
      - POSTGRES_HOST_AUTH_METHOD=trust
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    ports:
      - '5432:5432'
    # Logging for every query - can comment out the entire line to disable
    #     Reference: https://stackoverflow.com/a/58806511
    command: ["postgres", "-c", "log_statement=all"]

volumes:
  postgres_data_product:

```

Success looks like:

![](https://honstain.com/content/images/2024/02/image-14.png)

```
db-1 | 2024-02-27 15:02:00.353 UTC [1] LOG: database system is ready to accept connections
```

Connect IntelliJ to the Database

![](https://honstain.com/content/images/2024/02/image-15.png)

It should only require you to set the user and password from the docker-compose file.

![](https://honstain.com/content/images/2024/02/image-16.png)

You won't have much to look at until you run the migrations.

![](https://honstain.com/content/images/2024/02/image-17.png)

### Run the Django Migrations

You can start running the `manage.py` commands to initialize your Django service.

```
python manage.py migrate
```

![](https://honstain.com/content/images/2024/02/image-18.png)

You can refresh the postgres schema in IntelliJ to view the results of the migration. Success looks like you now have a table called `usercore_user`. 

![](https://honstain.com/content/images/2024/02/image-19.png)

This is also a reasonable time to create a superuser for local development.

```
python manage.py createsuperuser
```

# Overview of the API

This service uses DRF [https://www.django-rest-framework.org/#installation](https://www.django-rest-framework.org/?ref=honstain.com#installation) to serve as a basic REST API.

The model here is just a laughably basic user with three fields.

```python
from django.db import models

class User(models.Model):
    name = models.CharField(max_length=200)
    age = models.IntegerField()
```

And we will make a basic DRF ModelViewSet for it.

```python
import structlog

from rest_framework import serializers, viewsets

from .models import User

logger = structlog.get_logger(__name__)

# Serializers define the API representation.
class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ["id", "name", "age"]

# ViewSets define the view behavior.
class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    def list(self, request, *args, **kwargs):
        logger.info("UserViewSet list called", size=str(len(self.queryset)))
        return super(UserViewSet, self).list(request, *args, **kwargs)

    def create(self, request, *args, **kwargs):
        logger.info("Creating a new user", body=request.data)
        return super(UserViewSet, self).create(request, *args, **kwargs)

```

Running the service `python manage.py runserver` if you haven't already will let us exercise the endpoint using the DRF UI.

[http://localhost:8000/usercore/users/](http://localhost:8000/usercore/users/?ref=honstain.com)

![](https://honstain.com/content/images/2024/03/image.png)

You also have the basic Django Admin UI [http://localhost:8000/admin/](http://localhost:8000/admin/?ref=honstain.com)

![](https://honstain.com/content/images/2024/03/image-3.png)

![](https://honstain.com/content/images/2024/03/image-4.png)

## IntelliJ HTTP Client

I found the IntelliJ HTTP client to be a handy way to exercise simple endpoints, postman would also work here.

[HTTP Client | IntelliJ IDEAExplore the features of the HTTP Client plugin: compose and execute HTTP requests, view responses, configure proxy settings, certificates, and more.![](https://jetbrains.com/apple-touch-icon.png)IntelliJ IDEA Help![](https://resources.jetbrains.com/storage/products/intellij-idea/img/meta/preview.png)](https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html?ref=honstain.com)

```
### GET request list
GET http://localhost:8000/usercore/users/
Accept: application/json

### GET request single record
GET http://localhost:8000/usercore/users/40000/
Accept: application/json

### POST request create single record
POST http://localhost:8000/usercore/users/
Accept: application/json
Content-Type: application/json

{"name":"Anthony", "age":2}
```

![](https://honstain.com/content/images/2024/03/image-2.png)

# Starting Gunicorn

The Django runserver is useful for local development, but we want to get a more capable web server more detailed investigation.

Since we should have already installed gunciorn with our python dependencies, we can start it using:

```
gunicorn --log-level debug --bind 0.0.0.0:8000 user_service.wsgi -w 1
```

This uses the wsgi module Django already created for us, and sets one default worker.

![](https://honstain.com/content/images/2024/03/image-5.png)

Shooting a few calls into the server should look something like this:

![](https://honstain.com/content/images/2024/03/image-6.png)

This service is also setup with structlog and emits JSON formatted logs to the `logs` folder in the project directory.

![](https://honstain.com/content/images/2024/03/image-7.png)

```json
tail -f json.log | jq

{
  "request": "GET /usercore/users/",
  "user_agent": "Apache-HttpClient/4.5.14 (Java/17.0.10)",
  "event": "request_started",
  "ip": "127.0.0.1",
  "request_id": "f4449541-2eea-4337-ad63-fb24de0c0d35",
  "timestamp": "2024-03-15T15:06:48.697754Z",
  "logger": "django_structlog.middlewares.request",
  "level": "info"
}
{
  "size": "3",
  "event": "UserViewSet list called",
  "ip": "127.0.0.1",
  "request_id": "f4449541-2eea-4337-ad63-fb24de0c0d35",
  "timestamp": "2024-03-15T15:06:48.767477Z",
  "logger": "usercore.views",
  "level": "info"
}
{
  "code": 200,
  "request": "GET /usercore/users/",
  "event": "request_finished",
  "ip": "127.0.0.1",
  "user_id": null,
  "request_id": "f4449541-2eea-4337-ad63-fb24de0c0d35",
  "timestamp": "2024-03-15T15:06:48.770240Z",
  "logger": "django_structlog.middlewares.request",
  "level": "info"
}

```

# Summary

At this stage you should now have a Django service with DRF that can serve a basic API via Gunicorn (and has logging, tests, and a real PostgreSQL database).

[GitHub - AnthonyHonstain/django-user-service: An example Django 5.0 service with DRF, postgres, gunicorn.An example Django 5.0 service with DRF, postgres, gunicorn. - AnthonyHonstain/django-user-service![](https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg)GitHubAnthonyHonstain![](https://opengraph.githubassets.com/304d3737c475e70ab218dc0b17d559156e075deffc62be48b058de916231d6c9/AnthonyHonstain/django-user-service)](https://github.com/AnthonyHonstain/django-user-service?ref=honstain.com)

In subsequent posts, we will explore more of having our [SQS consumer](https://honstain.com/asyncio-sqs-and-httpx/), call this service.