μDjango (micro Django) 🧬

A single file Django micro project created for demonstration purposes to be used in the same way as other Python frameworks.

© 2023 Paolo Melchiorre CC BY-SA “Paolo Melchiorre with Will Vincent at DjangoCon US 2023 sprints in Durham, North Carolina (USA)”
© 2023 Paolo Melchiorre CC BY-SA “Paolo Melchiorre with Will Vincent at DjangoCon US 2023 sprints in Durham, North Carolina (USA)”
Django under the hood (3 part series)
  1. Update annotated Django querysets using subqueries
  2. Django 3.2: Compressed fixtures, fixtures compression
  3. μDjango (micro Django) 🧬

TL;DR

from django import conf, http, urls
from django.core.handlers import asgi

conf.settings.configure(
    ALLOWED_HOSTS="*",
    ROOT_URLCONF=__name__,
)

app = asgi.ASGIHandler()


async def root(request):
    return http.JsonResponse(
        {"message": "Hello World"}
    )


urlpatterns = [urls.path("", root)]

🏛️ History

I created this code while working on an improvement to Will Vincent‘s Django Microframework repository, which was itself inspired by a talk that Carlton Gibson gave at DjangoCon US 2019: Using Django as a Micro-Framework.

Starting from that demonstration code I thought of a Django micro application that could be used in the same way as a minimal application used in other Python frameworks such as Flask or FastAPI.

I presented this code during the first sprint day of DjangoCon US 2023, together with Will Vincent and seeing the appreciation I decided to publish it in this repository.

μDjango presentation during the DjangoCon US 2023 sprints in Durham, North Carolina (USA)
© 2023 Paolo Melchiorre CC BY-NC-SA “μDjango presentation during the DjangoCon US 2023 sprints in Durham, North Carolina (USA)”

💡 Inspirations

Below I report the projects that inspired uDjango and explain how they did it.

🔬 Django Microframework

This is the code of the version I created as an improvement on Will Vincent’s “Django Microframework” project.

The goal of that repository is stated at the beginning:

How close can Django get to Flask’s five-line “Hello, World!” implementation?”.

from django.conf import settings
from django.core.handlers import wsgi
from django.core import management
from django.http import HttpResponse
from django.urls import path

settings.configure(
    ALLOWED_HOSTS="*",
    ROOT_URLCONF=__name__,
)

urlpatterns = [
    path(
        "",
        lambda request: HttpResponse(
            "Hello, Django!"
        ),
    )
]

if __name__ == "__main__":
    management.execute_from_command_line()
else:
    application = wsgi.WSGIHandler()

Starting from the previous version I further decreased the size of the file using lambda instead of the function, reduced the memory usage using ALLOWED_HOSTS instead of DEBUG, and made it possible to use the code with runserver or gunicorn.

⚗️ A minimal Flask application

This code snippet is found in the “Quickstart” in the Flask documentation.

The description for this code preceding this code specifies that:

A minimal Flask application looks something like this”

from flask import Flask

app = Flask(__name__)


@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"

The code is essential and it is also easy to understand what it does without reading anything else in the documentation.

⚡ The simplest FastAPI file

This code snippet is found in the “First Steps” in the FastAPI tutorial.

The description for this code preceding this code specifies that:

The simplest FastAPI file could look like this”

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello World"}

This code is as basic and easy to understand as Flask’s, but unlike that, it’s asynchronous and returns JSON.

🧬 μDjango (micro Django) code

Starting from my version of Django Microframework and the FastAPI example code I tried to create the simplest Django file to return JSON asynchronously that can be used with uvicorn.

from django import conf, http, urls
from django.core.handlers import asgi

conf.settings.configure(
    ALLOWED_HOSTS="*",
    ROOT_URLCONF=__name__,
)

app = asgi.ASGIHandler()


async def root(request):
    return http.JsonResponse(
        {"message": "Hello World"}
    )


urlpatterns = [urls.path("", root)]

The resulting code is slightly longer than that of FastAPI but follows its functionality and is easily understandable.

🧪 Try it

For those interested I have shown below the steps on how to test it in a local Python environment.

💻 Set Up

⚗️ Virtual environment

Creating and activating the virtual environment:

$ python3 -m venv .venv
$ source .venv/bin/activate

🧩 Requirements

Installing the required Python packages in the virtual environments:

$ python3 -m pip install django uvicorn

Code

Create a new file called main.py and update it as shown above.

🏃 Run

Start the server with uvicorn command.

$ uvicorn main:app --reload

INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [45573] using StatReload
INFO:     Started server process [45575]
INFO:     Waiting for application startup.
INFO:     ASGI 'lifespan' protocol appears unsupported.
INFO:     Application startup complete.

🔬 Check it

Open your browser at http://127.0.0.1:8000

You will see the JSON response as:

{ "message": "Hello World" }

⚠️ Disclaimer

This code is for demonstration purposes only and should not be used in production. However, the code is released without any guarantee from the author and no liability can be attributed. Use at your own risk.

🐙 GitHub

You can find the updated uDjango code in this GitHub repository of mine

💬 Sharing

Here’s where the μDjango (micro Django) project was shared online in case you want to re-share it.

🦣 Mastodon

🐦️ Twitter

📣 Django forum

⚖️ License

μDjango is licensed under the BSD 3-Clause License.