Django in one file? Or should i call it a mini Django?

Django in one file? Or should i call it a mini Django?

Nothing serious, just experimenting on Django Framework

ยท

5 min read

It's weekend and after a very busy week i am back in my home desk and navigating through my checklist. Though i had not put any priority on my checklist, my eye went to A Simple Django version for beginners. Frankly i forgot what was my real idea over it, but i know few of them

  1. Running Django inside a single file

  2. Simple file and folder structure

Running Django Inside a Single File

I came up with my own solution from my stackoverflow answers. See Screenshot below.

Reference: https://stackoverflow.com/a/59356081/7587197

So looks like Django in a single file is possible. Here, your views and URLs are inside this same file, but we face problem when dealing with models inside this file since Django works on App concept and has its own guidelines on implementing apps like creating apps.py models.py migrations package and so on

so now let's try to make it more readable and usable.

Simple file and folder structure

So, continuing from the single file solution, lets create couple of files to make the code readable. (I am assuming the root folder is mdj) so this means every files will stay inside it.

  1. urls.py

     urlpatterns = []
    
  2. views.py (empty file for now)

  3. manage.py (The main entry file)

     import sys
    
     SETTINGS = dict(
         SECRET_KEY='djangoISsoCOOL',
         DEBUG=True,
         ROOT_URLCONF='urls',  # so that it can denote urls.py
         INSTALLED_APPS=[],
    
     )
     if __name__ == "__main__":
         import django
         from django.conf import settings
         from django.core.management import execute_from_command_line
    
         settings.configure(**SETTINGS)
         django.setup()
    
         execute_from_command_line(sys.argv)
    

    lets run this with command python manage.py runserver and it works. Now, lets create a simple page to check if view and urls works.

# views.py
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world.")
# urls.py
from django.urls import path

import views # import the view
# Todo for you : try with other import style as well

urlpatterns = [
    path('', views.index),
]

Now, run the server again using python manage.py runserver and it works.

Now, let's make the model and database to work, but we will need to configure app for this, so create few files to configure

  1. apps.py

     from django.apps import AppConfig
    
     # just a random name, MDJ=mini django
     class MDJConfig(AppConfig):
         name = 'mdj' # name of the root folder
    
  2. models.py

  3. migrations package (migrations folder and an empty __init__.py file)

and register this apps config location on settings(manage.py file), INSTALLED_APPS as

# manage.py
SETTINGS = dict(
    ...
    INSTALLED_APPS=[
         'apps.MDJConfig',
    ],
    ...
)

Now, lets run the server using, and it did not work this time and we see the error as ModuleNotFoundError: No module named 'mdj'
this means, the module, which we assumed to be the root of our project, is not being recognized. So, lets add out root folder path into systems path so that it can be recognized.

Add these following in the manage.py file

import sys
from pathlib import Path

# BASE_DIR = parent of manage.py file
BASE_DIR = Path(__file__).resolve().parent 

# this line will do the magic
sys.path.append(str(BASE_DIR.parent))

And now, run the server, and it works.

now let's create our very first sample model

# models.py
from django.db import models

class Sample(models.Model):
    name = models.CharField(max_length=100)

Create migrations using command: python manage.py makemigrations and it works, the migration is created and placed under migrations folder

Now, before applying migrations, configure database (sqlite3 for demo)

# manage.py
SETTINGS = dict(
    ...
    DATABASES={
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
        }
    }
    ...
)

and apply migrations using command python manage.py migrate and everything works, the database is created and the migrations are reflected in the database.

Open up Django shell using command python manage.py shell to play with the model.

So, the final structure of the project will look like this,

  • manage.py (core entry point contains settings as well)

  • urls.py (all urls for the project)

  • views.py (all view functions and classes for the project)

  • apps.py (app level configurations)

  • models.py (the model file which contains db related works)

  • migrations/__init__.py (migrations folder and the empty __init__.py file to store migrations when python manage.py makemigrations command is used)

The final manage.py looks like this

import sys
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent
sys.path.append(str(BASE_DIR.parent))

SETTINGS = dict(
    BASE_DIR=BASE_DIR,
    SECRET_KEY='djangoISsoCOOL',
    DEBUG=True,
    ROOT_URLCONF='urls',  # so that it can denote urls.py
    INSTALLED_APPS=[
        'apps.MDJConfig',
    ],
    DATABASES={
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
        }
    }
)
if __name__ == "__main__":
    import django
    from django.conf import settings
    from django.core.management import execute_from_command_line

    settings.configure(**SETTINGS)
    django.setup()

    execute_from_command_line(sys.argv)

What next ?

  1. Change models to database which can be done by changing MODELS_MODULE_NAME on django/apps/config.py:10 Doing this, the app will now know it needs to load models from database.py file instead of models.py

  2. Changing migrations to databasehistory. To make this work series of changes needs to be done on django.core.management.commands.makemigrations.py file and django.db.migrations.writer.MigrationWriter. I still need to verify doing this myself, since i see lots of things are changed on Django core itself.

  3. default app name should not be appended when creating table name for models. To make this work, changes are required on django.db.models.options.Options.contribute_to_class to not add app_label if db_table for model is not given

  4. When (3) is fixed, root folder name can be changed to any without any problems. currently, root folder name is mdj which is hardcoded on some of the files

  5. When performing all this fixes, create fix and patch it in runtime through manage.py file

Find complete code at: https://github.com/shrawanx/mdj

At the end, i feel this current implementation has lots and lots of works to do before i can say what the title of this article says, but it was fun trying and experimenting. Happy weekend