Monday, April 30, 2012

Django as a micro framework, including models

The following can be used as a base when you want to avoid the normal structure Django imposes on your project, and you just want everything in a single file.

It is based on similar attempts by Ivan Sagalaev and Fahrzin Hemmati (especially this gist), and a post on stack overflow.

A thing that I consider an improvement over Fahrzin Hemmati's version is that models don't need the explicit app_label and __module__.

#
# Django as a microframework skeleton, by Allan Boll, 1 May 2012
# Based on http://softwaremaniacs.org/blog/2011/01/07/django-micro-framework/en/
# and https://gist.github.com/2219751
#

#
# Settings
#
appname = 'app'
from django.conf import settings
if not settings.configured:
    settings.configure(
        SITE_ID=1,
        TEMPLATE_DIRS=['.'],
        DATABASES = {
            'default':{
                'ENGINE':'django.db.backends.sqlite3',
                'NAME': 'db',
            }
        },
        DEBUG=True,
        TEMPLATE_DEBUG=True,
        ROOT_URLCONF = __name__,
        STATIC_URL='/static/',
        STATICFILES_DIRS=['./static/'],
        INSTALLED_APPS=(
            'django.contrib.auth',
            'django.contrib.contenttypes',
            'django.contrib.sessions',
            'django.contrib.messages',
            'django.contrib.staticfiles',
            'django.contrib.admin', 
        )
    )

#
# Models
#
from django.db import models

# Workaround to allow models in current file
import sys
sys.modules[appname+'.'] = sys.modules[__name__]
old_module_name = sys.modules[__name__].__name__
sys.modules[__name__].__name__ = appname+'.'

class SomeModel(models.Model):
    field_name = models.CharField(max_length=10)

# Continuation of workaround to allow models in current file
sys.modules[__name__].__name__ = old_module_name


#
# Views
#
from django.shortcuts import render

def index(request):
    out = []
    for obj in SomeModel.objects.all():
        out.append(obj.field_name)
    return render(request, 'index.html', {'s': ', '.join(out)})


#
# URL configuration
#
from django.conf.urls.defaults import patterns, url, include

urlpatterns = patterns('',
    (r'^$', index),
)


#
# Admin site
#
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin, GroupAdmin
from django.contrib.auth.models import User, Group

admin.site = admin.AdminSite()
admin.site.register(User, UserAdmin)
admin.site.register(Group, GroupAdmin)
admin.site.register(SomeModel)

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls))
) + urlpatterns


#
# Running
#
if __name__=='__main__':
    # Monkey patch get_app to allow models in current file
    get_app_orig = models.get_app
    def get_app(app_label,*a, **kw):
        if app_label==appname:
            return sys.modules[__name__]
        return get_app_orig(app_label, *a, **kw)
    models.get_app = get_app

    # Add models in current file to global list of apps
    models.loading.cache.app_store[type(appname+'.models',(),{'__file__':__file__})] = appname

    from django.core import management
    management.execute_from_command_line()