Using Django ORM without the framework

Django's ORM is really simple to use and migrations support is great. When I modify a model and run makemigrations it generates a migration from the changes, and I can apply it with migrate and I'm done.

I wanted to use it in a serverless function to write in a remote Postgres instance. Django doesn't have a separate package for it's ORM, but it's still possible to use it on its own.

Minimal boilerplate

First, I've created a manage.py to configure Django. It also runs the management CLI. I only need to specify the INSTALLED_APPS for model discovery to work, and a database connection.

#!/usr/bin/env python

def init_django():
    import django
    from django.conf import settings

    if settings.configured:
        return

    settings.configure(
        INSTALLED_APPS=[
            'db',
        ],
        DATABASES={
            'default': {
                'ENGINE': 'django.db.backends.postgresql',
                'NAME': 'myapp',
                'USER': 'myapp_user',
                'PASSWORD': 'myapp',
                'HOST': '127.0.0.1',
                'PORT': '5432',
            }
        }
    )
    django.setup()


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

    init_django()
    execute_from_command_line()

I've created a module called db to act as a Django app and placed a models.py in it.

# db/models.py
from django.db import models
from manage import init_django

init_django()

class Model(models.Model):
    id = models.AutoField(primary_key=True)
    created_at = models.DateTimeField(auto_now_add=True, db_index=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

# define models here
class Post(Model):
    ...

Django needs to initialized for models to work, that's why I call init_django() to initialize it before defining the models.

Here's how the final folder structure looks like:

.
|-- db
|   |-- __init__.py
|   `-- models.py
|-- manage.py
|-- requirements.txt

That's about it. Now I can build models and update the database schema:

# create a migration under `./db/migrations`
$ python manage.py makemigrations db 

# apply migrations
$ python manage.py migrate

To use the models, I import them directly like any other class.

from db.models import Post

for it in Post.objects.all():
    print(it)
Last updated: