[Fixed]-How do I write a single-file Django application?

12👍

You might want to consider Simon Willison’s library:

From the readme:

djng is a micro-framework that depends on a macro-framework (Django).

My definition of a micro-framework: something that lets you create an entire
Python web application in a single module:

import djng

def index(request):
    return djng.Response('Hello, world')

if __name__ == '__main__':
    djng.serve(index, '0.0.0.0', 8888)

[…]

👤ars

15👍

Getting started with Django can be pretty easy too. Here’s a 10-line single-file Django webapp:

import os
from django.conf.urls.defaults import patterns
from django.http import HttpResponse
filepath, extension = os.path.splitext(__file__)
ROOT_URLCONF = os.path.basename(filepath)

def yoohoo(request):
    return HttpResponse('Yoohoo!')

urlpatterns = patterns('', (r'^hello/$', yoohoo))

Check out my blog post Minimal Django for details.

6👍

This is a simple CMS implemented in Django, as a single file. It was written by Paul Bissex. Some of it has been “golfed” and could do with a bit of expansion, but it’s still relatively easy to read.

The source has vanished from his pastebin, but I saved it:

#!/usr/bin/env python
"""
jngo -- The unhealthily compressed Django application.

Usage: ./jngo.py

Assuming a working install of Django (http://djangoproject.com/) and SQLite
(http://sqlite.org), this script can be executed directly without any other 
preparations -- you don't have to do `setup.py install`, it doesn't 
need to be on your Python path, you don't need to set DJANGO_SETTINGS_MODULE,
you don't need a webserver. You don't even need content -- the first time it's 
run, it will create a SQLite database in the same directory as the script 
and populate it with sample pages.

Features:

* Editable content on all pages
* Dynamically generated navigation buttons
* Optional private-access pages
* Optional per-page comments
* RSS feed of latest comments, with autodiscovery

Author: Paul Bissex <pb@e-scribe.com>
URL: http://news.e-scribe.com/
License: MIT

FAQS: 

Q: Should I use this as an example of excellent Django coding practices?
A: Um, no. This is pretty much the opposite of excellent Django coding practices.

Q: Why did you do such a terrible thing?
A: At first, it was just a perverse experiment. It ended up being a
good way to refresh my memory on some Django internals, by trying all
kinds of things that broke in weird ways.
"""

#--- Settings ---
NAME = ROOT_URLCONF = "jngo"
DEBUG = TEMPLATE_DEBUG = True
SITE_ID = 3000
HOSTNAME_AND_PORT = "127.0.0.1:8000"
DATABASE_ENGINE = "sqlite3"
DATABASE_NAME = NAME + ".db"
INSTALLED_APPS = ["django.contrib.%s" % app for app in "auth admin contenttypes sessions sites flatpages comments".split()]
TEMPLATE_LOADERS = ('django.template.loaders.app_directories.load_template_source', NAME + '.template_loader')
MIDDLEWARE_CLASSES = ('django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware')
TEMPLATE_CONTEXT_PROCESSORS = (NAME + '.context_processor', "django.core.context_processors.auth", "django.core.context_processors.request")

#--- Template loader and templates ---
def template_loader(t, _):
    from django.template import TemplateDoesNotExist
    try:
        return {
            'base.html': """<html><head><title>{{ flatpage.title }}</title><link rel='alternate' type='application/rss+xml' href='/feed/'><style type="text/css">body { margin: 15px 50px; background: #eee; color: #343; font-family: sans-serif; } ul { padding: 0; } li { display: inline; background: #383; padding: 4px 8px; margin: 3px; } li:hover { background: #252; } dd { border-bottom: 1px dotted #666; } a { color: #383; text-decoration: none; } li a { color: #fff; } .anav { background: #141; } .rnav a { color: #ff4; } .error { color: #e22; } #footer { border-top: 1px dotted #555; font-size: 80%; color: #555; margin-top: 15px } #comments { background: #ddd; margin-top: 20px; padding: 10px; } dt { font-weight: bold; margin-top: 1em; }</style></head><body><ul>{% for nav in navs %}<li class="{% ifequal nav.url flatpage.url %}anav {% endifequal %}{% if nav.registration_required %}rnav {% endif %}"><a href="{{ nav.url }}">{{ nav.title }}</a></li>{% endfor %}</ul>{% block content %}{% endblock %}<div id="footer">{% if request.user.is_staff %}<a href="javascript:(function(){if(typeof%20ActiveXObject!='undefined'){var%20x=new%20ActiveXObject('Microsoft.XMLHTTP')}else%20if(typeof%20XMLHttpRequest!='undefined'){var%20x=new%20XMLHttpRequest()}else{return;}x.open('GET',location.href,false);x.send(null);try{var%20type=x.getResponseHeader('x-object-type');var%20id=x.getResponseHeader('x-object-id');}catch(e){return;}document.location='/admin/'+type.split('.').join('/')+'/'+id+'/';})()">Edit this page</a> (as staff user <a href="/admin/">{{ request.user }}</a>)<br>{% endif %}Powered by <a href="http://djangoproject.com/">Django</a> {{ version }}<br></div></body></html>""",
            'flatpages/default.html': """{% extends "base.html" %}{% load comments %}{% block content %}<h1>{{ flatpage.title }}</h1>{{ flatpage.content }}{% if flatpage.enable_comments %}<div id="comments">{% get_free_comment_list for flatpages.flatpage flatpage.id as comments %}<h3>Comments!</h3><dl>{% for comment in comments %}{% include "comment.html" %}{% endfor %}</dl>{% free_comment_form for flatpages.flatpage flatpage.id %}</div>{% endif %}{% endblock %}""",
            'comments/free_preview.html': """{% extends "base.html" %}{% block content %}<h1>Comment preview</h1><dl>{% include "comment.html" %}</dl><form action='.' method='post'><input type='hidden' name='gonzo' value='{{ hash }}'><input type='hidden' name='options' value='{{ options }}'><input type='hidden' name='comment' value='{{ comment.comment }}'><input type='hidden' name='person_name' value='{{ comment.person_name }}'><input type='hidden' name='target' value='{{ target }}'><input type='submit' name='post' value='Post comment'></form>{% endblock %}""", 
            'comments/posted.html': """{% extends "base.html" %}{% block content %}<h1>Comment posted</h1><p>Thanks for posting!</p> <p><a href='{{ object.get_absolute_url }}'>Continue</a></p>{% endblock %}""",
            'comment.html': """<dt>{{ comment.person_name }} said:</dt> <dd>{{ comment.comment }}</dd>""",
            'registration/login.html': """{% extends "base.html" %}{% block content %}{% if form.has_errors %}<h2 class="error">Wrong!</h2>{% endif %}<p>This page is top secret, so you need to log in.</p><form method="post" action=".">Username: {{ form.username }}<br>Password: {{ form.password }}<br><input type="submit" value="login"><input type="hidden" name="next" value="{{ next }}"></form>{% endblock %}"""
            }[t], ''
    except KeyError:
        raise TemplateDoesNotExist
template_loader.is_usable = True

#--- Context processor ---
def context_processor(request):
    from django.contrib.flatpages.models import FlatPage
    navs = FlatPage.objects.all().values("url", "title", "registration_required")
    from django import get_version
    return { 'navs': navs, 'version': get_version() }

#--- RSS Feed (hacky wrapper function needed because of jngo's one-file setup) ---
def feed(*args, **kwargs):
    from django.contrib.comments.feeds import LatestFreeCommentsFeed
    return LatestFreeCommentsFeed(*args, **kwargs)

#--- URLconf ---
from django.conf.urls.defaults import *
urlpatterns = patterns("", 
    (r"^admin/", include("django.contrib.admin.urls")), 
    (r"^comments/", include("django.contrib.comments.urls.comments")), 
    (r"^accounts/login/$", "django.contrib.auth.views.login"),
    (r"^(feed)/$", "django.contrib.syndication.views.feed", {'feed_dict': {'feed': feed}}),
    )

#--- Execution ---
if __name__ == "__main__":
    import os, sys
    from django.core.management import call_command
    here = os.path.dirname(__file__)
    sys.path.append(here)
    os.environ["DJANGO_SETTINGS_MODULE"] = NAME
    if not os.path.isfile(os.path.join(here, DATABASE_NAME)):
        from django.contrib.auth.create_superuser import createsuperuser
        from django.contrib.flatpages.models import FlatPage
        from django.contrib.sites.models import Site
        call_command("syncdb")
        createsuperuser()
        site_obj = Site.objects.create(id=SITE_ID, domain=HOSTNAME_AND_PORT)
        FlatPage.objects.create(url="/", title="Home", content="Welcome to %s!" % NAME).sites.add(site_obj)
        FlatPage.objects.create(url="/stuff/", enable_comments=True, title="Stuff", content="This is a page about stuff.").sites.add(site_obj)
        FlatPage.objects.create(url="/topsecret/", title="Top Secret", content="Now you know.", registration_required=True).sites.add(site_obj)
    call_command("runserver", HOSTNAME_AND_PORT)

4👍

Tested with Django 1.7

#!/usr/bin/env python
import os
import sys
from django.conf import settings
from django.conf.urls import patterns, include, url
from django.http import HttpResponse

filename = os.path.splitext(os.path.basename(__file__))[0]

urlpatterns = patterns('',
    url(r'^$', '%s.home' % filename, name='home'),
)

def home(request):
    return HttpResponse('hello')

if __name__ == "__main__":
    settings.configure(
        DEBUG=True,
        MIDDLEWARE_CLASSES = [],
        ROOT_URLCONF = filename
    )

    from django.core.management import execute_from_command_line
    execute_from_command_line([sys.argv[0], 'runserver'])
👤un1t

3👍

Most of the single file django examples found over the web lack support for model since django somehow require models to be declared in models.py file in each INSTALLED_APP. Finally I found an example that include support for model:-

http://fahhem.com/blog/2011/10/django-models-without-apps-or-everything-django-truly-in-a-single-file/

The link to the django wiki on models creation also worth reading. And the full code which also include admin:-

https://gist.github.com/2219751

👤k4ml

3👍

Here a working example for Django 2.2

import os
import sys
from django.conf import settings
from django.core.management import execute_from_command_line
from django.http import HttpResponse
from django.urls import path

fname = os.path.splitext(os.path.basename(__file__))[0]
urlpatterns = [path(r'', lambda r: HttpResponse('Hello, world!'))]

if __name__ == "__main__":
    settings.configure(DEBUG=True, MIDDLEWARE_CLASSES=[], ROOT_URLCONF=fname)
    execute_from_command_line([sys.argv[0], 'runserver'])
👤C14L

2👍

Then what you need is not Django.
What you need is exactly what micropy does.

👤Santi

1👍

John’s answer quoting the jngo app by Paul Bissex is impressive, but it’s sadly broken under Django 1.7.

I did a bunch of digging and created 𝜇Django to show how to run a model class with a SQLite database in a single Python file. I plan to use it for posting questions about Django model classes. If you want some of the other parts from jngo, you might be able to graft them onto this. Fahrzin Hemmati has posted an example that seems similar and includes the full Django: web server, models, management commands. I haven’t tried it out, yet.

# Tested with Django 1.9.2
import sys

import django
from django.apps import apps
from django.apps.config import AppConfig
from django.conf import settings
from django.db import connections, models, DEFAULT_DB_ALIAS
from django.db.models.base import ModelBase

NAME = 'udjango'


def main():
    setup()

    class Person(models.Model):
        first_name = models.CharField(max_length=30)
        last_name = models.CharField(max_length=30)

    syncdb(Person)

    p1 = Person(first_name='Jimmy', last_name='Jones')
    p1.save()
    p2 = Person(first_name='Bob', last_name='Brown')
    p2.save()

    print ', '.join([p.first_name for p in Person.objects.all()])


def setup():
    DB_FILE = NAME + '.db'
    with open(DB_FILE, 'w'):
        pass  # wipe the database
    settings.configure(
        DEBUG=True,
        DATABASES={
            DEFAULT_DB_ALIAS: {
                'ENGINE': 'django.db.backends.sqlite3',
                'NAME': DB_FILE}},
        LOGGING={'version': 1,
                 'disable_existing_loggers': False,
                 'formatters': {
                    'debug': {
                        'format': '%(asctime)s[%(levelname)s]'
                                  '%(name)s.%(funcName)s(): %(message)s',
                        'datefmt': '%Y-%m-%d %H:%M:%S'}},
                 'handlers': {
                    'console': {
                        'level': 'DEBUG',
                        'class': 'logging.StreamHandler',
                        'formatter': 'debug'}},
                 'root': {
                    'handlers': ['console'],
                    'level': 'WARN'},
                 'loggers': {
                    "django.db": {"level": "WARN"}}})
    app_config = AppConfig(NAME, sys.modules['__main__'])
    apps.populate([app_config])
    django.setup()
    original_new_func = ModelBase.__new__

    @staticmethod
    def patched_new(cls, name, bases, attrs):
        if 'Meta' not in attrs:
            class Meta:
                app_label = NAME
            attrs['Meta'] = Meta
        return original_new_func(cls, name, bases, attrs)
    ModelBase.__new__ = patched_new


def syncdb(model):
    """ Standard syncdb expects models to be in reliable locations.

    Based on https://github.com/django/django/blob/1.9.3
    /django/core/management/commands/migrate.py#L285
    """
    connection = connections[DEFAULT_DB_ALIAS]
    with connection.schema_editor() as editor:
        editor.create_model(model)

main()

1👍

The code below represents a single file django app. It was shamelessly copied from this interesting book chapter, and can be run using python singlefile.py runserver (if the file is called singlefile.py). Works at least in Django 1.9 and 2.0.

import sys
from django.conf import settings

settings.configure(
    DEBUG=True,
    SECRET_KEY='thisisthesecretkey',
    ROOT_URLCONF=__name__,
    MIDDLEWARE_CLASSES=('django.middleware.common.CommonMiddleware',
                        'django.middleware.csrf.CsrfViewMiddleware',
                        'django.middleware.clickjacking.XFrameOptionsMiddleware')
)

from django.conf.urls import url
from django.http import HttpResponse


def index(request): return HttpResponse('Hello World')

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

if __name__ == "__main__":
    from django.core.management import execute_from_command_line
    execute_from_command_line(sys.argv)

… it does look a lot like the answer by un1t, except for some details.

👤djvg

1👍

Most of the single file Django examples found over the web lack support for models since Django somehow requires models to be declared in a models.py file in each INSTALLED_APP, but here is an example that includes support for models:

http://fahhem.com/blog/2011/10/django-models-without-apps-or-everything-django-truly-in-a-single-file/

The link there to the Django wiki on models creation is also worth reading.

Full code from k4ml including admin (circa 2012):
https://gist.github.com/2219751

Version of Hemmati’s original tweaked for Django 2.2 & 3.1:

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
)
SETTINGS['DATABASES']={
    'default':{
        'ENGINE':'django.db.backends.sqlite3',
        'NAME':rel_path('db')
    }
}

if __name__=='__main__':
    settings.configure(**SETTINGS)

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

from django.urls import path
from django.http import HttpResponse
def view_name(request):
    return HttpResponse('response text')
urlpatterns = [ path('',view_name) ]

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

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

from django.db import models
from django.apps import apps
class SomeModel(models.Model):
    class Meta: app_label = this
    __module__ = this
    field_name = models.CharField(max_length=10)

if __name__=='__main__':
    # override get_app to work with us
    def get_app(app_label,*a, **kw):
        if app_label==this:
            return sys.modules[__name__]
        return apps.get_app_config(app_label,*a,**kw).models_module
    models.get_app = get_app
    apps.app_configs[type(this+'.models',(),{'__file__':__file__})] = this

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()
    

    

0👍

Well, the easiest way to do that is to mimic the django project arbo in one file. So in one module, assure there is :

Root_module :
    Root_module.settings
    Root_module.urls
    Root_module.app_in_the_module
    Root_module.app_in_the_module.models
    Root_module.app_in_the_module.views

Then code is as a normal Django project. What you must know is that Django does not need anything to be in a specific place. Standard names and paths are at beat, convention, at worst, shortcut to prevent you from defining a setting.

If you know Django very well, you don’t even need to mimic the arbo, just write you django app making all the data from the above modules interconnected the way they should be.

Leave a comment