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/