Joseph Jude

Consult . Code . Coach

Django application as a stand-alone desktop application


code . python . django

There are few options available to package Django as a stand-alone desktop apps.

They are:

I read pages after pages and spent about a week in making a desktop app of SOL. I didn't make much progress and was very frustrated. (I wrote about it here. After a time, I switched to py2exe, as I was not able to locate much info about cx_freeze.

I used py2exe, sqlite and cherrypy for packaging as a desktop app. As it is only for demo purpose, I would've preferred to have the default development server itself. But I don't know how to do it; and info about cherrypy was readily available.

Fundamentally, you need to import all of the required Django modules. That takes the most of the time. Whenever I got, 'module' object has no attribute 'xxxx', I had to trace it to one of Django's module and import it.

Once I got all of the modules, I had to integrate with CherryPy. It wasn't difficult as info was already available. However, admin css were not delivered. I read through AdminMediaHandler code and understood that I had to pass an absolute path for admin media folder. That got me both local media and admin media done.

I had to make only one change to settings.py. I replaced

os.path.dirname(os.path.abspath(__file__))

with sys.argv[0]

I was glad that I persevered to make this. Here I post the setup, imports and the build script with the hope that it might be useful for others.

This is the first file - sol.py

  #!/usr/bin/env python
  # -*- coding: UTF-8 -*-
  import os, sys

  os.environ['DJANGO_SETTINGS_MODULE'] = "settings"
  #these pertain to your application
  import sol.models
  import sol.views
  import urls
  import manage
  import settings
  #these are django imports
  import django.template.loaders.filesystem
  import django.template.loaders.app_directories
  import django.middleware.common
  import django.contrib.sessions.middleware
  import django.contrib.auth.middleware
  import django.middleware.doc
  import django.contrib.auth
  import django.contrib.contenttypes
  import django.contrib.sessions
  import django.contrib.sessions.backends.db
  import django.contrib.sites
  import django.contrib.admin
  import django.core.cache.backends
  import django.db.backends.sqlite3.base
  import django.db.backends.sqlite3.introspection
  import django.db.backends.sqlite3.creation
  import django.db.backends.sqlite3.client
  import django.template.defaulttags
  import django.template.defaultfilters
  import django.template.loader_tags

  import django.contrib.admin.urls
  from django.conf.urls.defaults import *
  import django.contrib.admin.views.main
  import django.core.context_processors
  import django.contrib.auth.views
  import django.contrib.auth.backends
  import django.views.static
  import django.contrib.admin.templatetags.adminmedia
  import django.contrib.admin.templatetags.adminapplist
  import django.contrib.admin.templatetags.admin_list
  import django.contrib.admin.templatetags.admin_modify
  import django.contrib.admin.templatetags.log
  import django.contrib.admin.views.auth
  import django.contrib.admin.views.doc
  import django.contrib.admin.views.template
  import django.conf.urls.shortcut
  import django.views.defaults

  #dont need to import these pkgs
  #need to know how to exclude them
  import email.mime.audio
  import email.mime.base
  import email.mime.image
  import email.mime.message
  import email.mime.multipart
  import email.mime.nonmultipart
  import email.mime.text
  import email.charset
  import email.encoders
  import email.errors
  import email.feedparser
  import email.generator
  import email.header
  import email.iterators
  import email.message
  import email.parser
  import email.utils
  import email.base64mime
  import email.quoprimime
  import django.core.cache.backends.locmem
  import django.templatetags.i18n
  import django.views.i18n

  #let us hook up cherrypy
  #is it possible to hook up the dev server itself?
  from cherrypy import wsgiserver
  import cherrypy
  from django.core.handlers.wsgi import WSGIHandler
  from django.core.servers.basehttp import AdminMediaHandler

  if __name__ == "__main__":
      print '*****************************************************'
      print 'Open your browser and point to http://localhost:8000'
      print 'To close, press ctrl-c'
      print ''
      print 'local user id is: jjude; password is also jjude'
      print 'admin user id is: admin; password is also admin'
      print '*****************************************************'
      os.environ["DJANGO_SETTINGS_MODULE"] = "settings"
      # Set up site-wide config first so we get a log if errors occur.

      cherrypy.config.update({'environment': 'production',
                              'log.error_file': 'site.log',
                              'log.screen': False})

      try:
          sys.path.insert(0,"..")
          #2nd param to AdminMediaHandler should be absolute path to the admin media files
          cherrypy.tree.graft(AdminMediaHandler(WSGIHandler(),media_dir=os.path.dirname(os.path.abspath(sys.argv[0])) + settings.ADMIN_MEDIA_PREFIX), '/')
          cherrypy.server.socket_port = 8000
          cherrypy.server.quickstart()
          cherrypy.engine.start()

      except KeyboardInterrupt:
          cherrypy.server.stop()

This is setup.py

 from distutils.core import setup
  import py2exe
  import glob

  setup(
      options = {"py2exe": {"compressed": 1,
                            "optimize": 2,
                            "ascii": 1,
                            "bundle_files": 1,
                            "packages":["encodings"],
                             "excludes" : ["pywin", "pywin.debugger", "pywin.debugger.dbgcon","pywin.dialogs",
                                         "pywin.dialogs.list","Tkconstants","Tkinter","tcl"],

                              }},
      #these are the data files like templates, site media and admin media
      data_files = [(".",["sol.db"]),
          ("templates",glob.glob("templates\*.*")),
          #("files",glob.glob("files\*.*")),
          ("media",glob.glob("media\*.*")),
          ("media\css",glob.glob("media\css\*.*")),
          ("templates\admin",glob.glob("C:\Python25\Lib\site-packages\django\contrib\admin\templates\admin\*.*")),
          ("templates\admin\auth\user",glob.glob("C:\Python25\Libsite-packages\django\contrib\admin\templates\admin\auth\user\*.*")),
          ("templates\admin_doc",glob.glob("C:\Python25\Lib\site-packages\django\contrib\admin\templates\admin_doc\*.*")),
          ("templates\widget",glob.glob("C:\Python25\Lib\site-packages\django\contrib\admin\templates\widget\*.*")),
          ("templates\registration",glob.glob("C:\Python25\Lib\site-packages\django\contrib\admin\templates\registration\*.*")),
          ("adminmedia\css",glob.glob("C:\Python25\Lib\site-packages\django\contrib\admin\media\css*.*")),
          ("adminmedia\js",glob.glob("C:\Python25\Lib\site-packages\django\contrib\admin\media\js\*.*")),
          ("adminmedia\img",glob.glob("C:\Python25\Lib\site-packages\django\contrib\admin\media\img\*.*")),
          ],
      zipfile = None,
      console=['sol.py'],
      )

This is the build script.

python -OO setup.py py2exe --b 2 --optimize 2 --dist-dir y:sol rd /s /q build

You can download the demo from the repo. I'll keep updating these scripts as I learn more. So get the updated scripts from my repo.

If you are to engage in such a exercise, you need lot of patience.

Next steps:

Reference:


Like the post? Retweet it. Got comments? Reply.

Making #django application as a stand-alone desktop application by @jjude: https://t.co/AY3KsOUVN1

— Joseph Jude (@jjude) September 26, 2016
Share this on: Twitter / /

Comments

comments powered by Disqus