Single File Django Application

Single file django application

I searched how to write a single file Django app so I can test Django features fast. I searched the internet and found the safest single-file Django application is shared here, but I couldn’t find any example that includes Django models, so I made some additions to this code.

To make makemigrations run, we need to understand Python’s way of searching the modules in the sys.path list.

According to the doc, sys.path is “a list of strings that specifies the search path for modules. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string.” So if we use Python through a command line then the first element will be an empty string that indicates the current running directory.

Django uses the same way to find installed apps. After we create a project django-admin startproject project_name and run server, we can see that the sys.path[0] is assigned to the project root folder like /home/nurettin/PycharmProjects/project_name in my case. In that directory, Django is able to find the apps whose name is stated in INSTALLED_APPS. But in our case it won’t work, so we need to:

  • treat that single file’s parent folder as a project root folder -> Append parent directory to sys.path
  • provide the file’s directory as an app folder -> We will make this in makemigrations command
  • treat that single file as an app -> initiate an app label in the model’s meta and put this in INSTALLED_APPS
    • Normally, Django knows these apps and their configuration via their AppConfigs, but if you look at the documentation of app_label, it says “if a model is defined outside of an application in INSTALLED_APPS, it must declare which app it belongs to”, so we can define an app name in the model’s Meta.app_label.

I made the necessary changes, created an example City model, and gave the app label inside its Meta class. The final code is as below:

import html
import os
import sys

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

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(BASE_DIR))
APP_LABEL = os.path.basename(BASE_DIR)

settings.configure(
    DEBUG=(os.environ.get("DEBUG", "") == "1"),
    ALLOWED_HOSTS=["*"],
    SECRET_KEY="supersecretkey",
    ROOT_URLCONF=__name__,
    MIDDLEWARE=["django.middleware.common.CommonMiddleware"],
    DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
    INSTALLED_APPS=[APP_LABEL],
    DATABASES={
        "default": {
            "ENGINE": "django.db.backends.sqlite3",
            "NAME": os.path.join(BASE_DIR, "db.sqlite3"),
        }
    },
)


def index(request):
    name = request.GET.get("name", "World")
    return HttpResponse(f"Hello, {html.escape(name)}!")


urlpatterns = [
    path("", index),
]

app = get_wsgi_application()

from django.db import models


class City(models.Model):
    name = models.CharField(
        max_length=128, blank=False, null=False, unique=True
    )
    value = models.IntegerField(default=-1, blank=False, null=False)

    class Meta:
        app_label = APP_LABEL


if __name__ == "__main__":
    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

Running the code

Our settings are ready. All we need to do is to run migration commands. While we run makemigrations and migrate commands, we will provide the APP_LABEL value which was the root folder name, and we need to run our command inside the project folder:

nurettin@laptop:~/PycharmProjects/project_name$ pwd
/home/nurettin/PycharmProjects/project_name

nurettin@laptop:~/PycharmProjects/project_name$ python main.py makemigrations project_name
Migrations for 'project_name':
  migrations/0001_initial.py
    - Create model City

nurettin@laptop:~/PycharmProjects/project_name$ python main.py migrate project_name
Operations to perform:
  Apply all migrations: project_name
Running migrations:
  Applying project_name.0001_initial... OK

We successfully created the migration file and corresponding table inside the project folder.

Importing the models in shell_plus

nurettin@laptop:~/PycharmProjects/project_name$ python main.py shell_plus
>>> from django.apps import apps
>>> city_model = apps.get_app_config('project_name').models['city']
>>> city_model.objects.all()

Now it’s time to test fast learn fast.

Source:
Django versus Flask with Single File Applications