Index ¦ Archives  ¦ Atom  ¦ RSS

Django Models without Apps OR Everything Django Truly in a Single File

This problem has bugged me for a few years actually, I have tried over and over again to use a single file for all of a Django projects' python code. This has proved very possible as long as your project did not have models, because no tutorial or howto online includes a model. Today I found out how to create models without putting them in a separate file and directory (models.py inside an app folder) so I would like to create the ultimate single-file Django tutorial.

Basics

At the top of the file, add the following lines.

from os import path as osp
def rel_path(*p): return osp.normpath(osp.join(rel_path.path, *p))
rel_path.path = osp.abspath(osp.dirname(__file__))
this = osp.splitext(osp.basename(__file__))[0]

from django.conf import settings
SETTINGS = dict(
    DATABASES = {},
    DEBUG=True,
    TEMPLATE_DEBUG=True,
    ROOT_URLCONF = this
)
if __name__=='__main__':
    settings.configure(**SETTINGS)

And add these at the bottom.

if __name__ == '__main__':
    from django.core import management
    management.execute_from_command_line()

Urls and Views

from django.conf.urls.defaults import patterns
from django.http import HttpResponse

def view_name(request):
    return HttpResponse('response text')

urlpatterns = patterns('', (r'^regex here$', view_name) )

Templates

from django.template.response import TemplateResponse
def view_name(request):
    return TemplateResponse(request, 'template.html', {'variable':'value'})

Add this before the settings.configure call:

SETTINGS['TEMPLATE_DIRS'] = (rel_path(),),

Models

And now for the main event!

from django.db import models

class SomeModel(models.Model):
    class Meta: app_label = this
    __module__ = this
    field_name = models.CharField(max_length=10)

Add this after your models, but before you use them in views and such:

if __name__=='__main__':
    # override get_app to work with us
    get_app_orig = models.get_app
    def get_app(app_label,*a, **kw):
        if app_label==this:
            return sys.modules[__name__]
        return get_app_orig(app_label, *a, **kw)
    models.get_app = get_app

    models.loading.cache.app_store[type(this+'.models',(),{'__file__':__file__})] = this

Add this before the settings.configure call:

SETTINGS['DATABASES']={
    'default':{
        'ENGINE':'django.db.backends.sqlite3',
        'NAME':rel_path('db')
    }
}

Yes, it's really that easy!

Management Commands

These will add commands, so when you run your program you can do more than just runserver.

from django.core.management import get_commands, BaseCommand
class MyCommand(BaseCommand):
    def handle(self, **options):
        pass # do your stuff here like a normal command

if __name__ == '__main__':
    commands = get_commands()
    commands['management_command_name'] = MyCommand()

Add this for each command, though you can combine all the "if __name__..." bits together at the bottom of the file, making sure to add the commands modifier before you execute.

Attributions

Most of the info came from mini-django by Tim Watts: http://readevalprint.com/mini-django/

The missing piece for models comes from Django's own wiki: https://code.djangoproject.com/wiki/DynamicModels#Ageneral-purposeapproach

And lots of reading of django's own code, especially django/core/management/

© Fahrzin Hemmati. Built using Pelican. Theme by Giulio Fidente on github.