Simple Django Tutorial

Post Under Development

Content

  1. Prerequisites
  2. Create a Project (Site)
  3. Hello App
  4. Contacts App

1. Prerequisites

  1. Installed Django 1.9+
  2. Above is Running on Python 3

2. Create a Project (Site)

N.B. Django conflates Project with Site.

Run django-admin startproject

Assume CODE_HOME stands for the directory where you’d like to store your code.

cd CODE_HOME
django-admin startproject mysite

Here’s the resulting file structure. N.B. The top directory, named mysite, CONTAINS a sub-directory with the SAME NAME, mysite.

CODE_HOME/
    mysite/
        manage.py
        mysite/
            __init__.py
            settings.py
            urls.py
            wsgi.py

Verify the Site

cd CODE_HOME/mysite
python manage.py runserver

You should see something like the following.

Performing system checks...

System check identified no issues (0 silenced).

[FOR THIS TUTORIAL, STUFF HERE, WAS DELETED.]

Django version 1.9.5, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

Browsing to http://127.0.0.1:8000/ you should see something like the following.

It worked!
Congratulations on your first Django-powered page.

3. Hello App

Let’s make a Hello app and call it “hello”.

N.B. We will run django-admin startapp NOT startproject.
Again, assume CODE_HOME stands for the directory where you “stored your code”.
Remember the resulting tree from startproject was as follows.

CODE_HOME/
    mysite/
        manage.py
        mysite/
            __init__.py
            settings.py
            urls.py
            wsgi.py

Run django-admin startapp

cd CODE_HOME/mysite 
django-admin startapp hello

Here’s the resulting tree.

CODE_HOME/
    mysite/
        db.sqlite3
        manage.py
        hello/
            __init__.py          
            admin.py
            apps.py
            models.py
            tests.py
            views.py
            migrations/
                __init__.py    
        mysite/
            __init__.py
            settings.py
            urls.py
            wsgi.py

Add hello to settings.py

We need to edit the Site file settings.py to tell Django our hello app exists. Add one line to CODE_HOME/mysite/mysite/settings.py as shown.

# CODE_HOME/mysite/mysite/settings.py

...
# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'hello',                     # add this line
]
...

Add hello to our Site urls.py file.

Add one line in urlpatterns to CODE_HOME/mysite/mysite/urls.py as shown.

# CODE_HOME/mysite/mysite/urls.py

#[FOR THIS TUTORIAL, STUFF HERE, WAS DELETED.]

urlpatterns = [
    url(r'^hello/', include('hello.urls', namespace="hello")), # add this line
    url(r'^admin/', admin.site.urls),
]

A Great Seed for Angular Material – Cordova Apps

A Great App Seed from Mario Aleo

Mario Aleo has published a GREAT App Seed for Cordova – Angular Material Apps on his GitHub Repository cordova-angular-angularMaterial-seed.

When i first encountered a reference to the seed here on stackOverflow, I said “This looks like EXACTLY what i need. It [the Repository Documentation] is VERY WELL EXPLAINED”.

Since then, in the space of just a few hours, I have used Mario’s seed to produce a running app on my tablet. Not only is the GitHub Repository documentation GREAT, but the code in the Mario’s seed is SUPERBLY READABLE. I will learn a lot from using your code, Mario. Thanks.

Also, Mario says that his work is based on AngularJS Best Practices: Directory Structure by Adnan Kukic (@kukicadnan).

Thanks to BOTH of you.

Love and peace,

Joe

Execute Shell Commands from a Python GUI App

GUI Execute Commands

Here’s my Python – TKinter App that takes a set of Shell Commands from a .json file and displays them for individual execution when a button is clicked. Write these frequently used commands once and let the GUI program remember their syntax.

Keep 3 files in the same directory:

  • guiExecuteCommands.py The TKInter Program
  • config.json The Configuration Data
  • cmds.json The Initial Command Set

Contents

  • The TKInter Program File – guiExecuteCommands.py
  • The Configuration Data File – config.json
  • The Initial Command Set – cmds.json
  • A Screenshot of the TKInter Program
  • A run log of the program

The TKInter Program File – guiExecuteCommands.py

Here is the guiExecuteCommands.py file.

#!/usr/bin/python
# -*- coding: utf-8 -*-
# guiExecuteCommands.py
import sys, os, time, subprocess, json, atexit

# if not('.' in sys.path): sys.path.append('.')
# from MyCommands import cmds

import Tkinter, tkFileDialog

class Theapp(Tkinter.Tk):
    def __init__(self,parent):

        # joe's init
        with open('config.json') as data_file:
            cfg_data = json.load(data_file)
        self.cfg_data = cfg_data 

        with open(cfg_data[0]['commandsf']) as data_file:
            cmds = json.load(data_file)
        self.cmds = cmds 


        atexit.register(self.on_exit) # http://stackoverflow.com/a/28664350/601770


        # /joe's init




        Tkinter.Tk.__init__(self,parent)
        self.parent = parent
        self.initialize()

    def on_exit(self):
        ''' http://stackoverflow.com/a/28664350/601770  
            save the state that has been changed
        '''

        self.cfg_data[0]['workingd'] = self.cwd.get()


        print "self.cwd.get(): %s"%(self.cwd.get())
        print "self.cfg_data: %s"%(self.cfg_data)

        with open('config.json', 'w') as f:
            json.dump(self.cfg_data, f)

    def execute_cmd(self, rnum):
        ''' C:\1d\PythonPjs\subprocessPjs\executeCommandsPj\executeCommands\executeCommands.py

        '''
        commandstring = self.cmd_entries[rnum].get()
        cwdpath = self.cwd.get()
        outstr = subprocess.check_call(commandstring, cwd=cwdpath, shell=True)  #  Convenience Function
        print outstr


    ## http://stackoverflow.com/a/16777523/601770   
    def bclick(self, rnum):
        def click():            
            self.execute_cmd(rnum)
        return click



    def browse2cwd(self):   
        """
        http://stackoverflow.com/questions/11295917/how-to-select-a-directory-and-store-the-location-using-tkinter-in-python
        http://tkinter.unpythonic.net/wiki/tkFileDialog
            find "def askdirectory(self):"
        """   
        tkFileDiaOpt4Dir = {}
        tkFileDiaOpt4Dir['initialdir'] = self.cwd.get()
        tkFileDiaOpt4Dir['mustexist'] = False
        tkFileDiaOpt4Dir['parent'] = self
        tkFileDiaOpt4Dir['title'] = 'Browse to set CWD.'

        self.cwd.set( tkFileDialog.askdirectory(**tkFileDiaOpt4Dir) )

        print "browse2cwd:  self.cwd.get(): %s"%(self.cwd.get())

    def initialize(self):
        self.cwd = Tkinter.StringVar()
        self.cwd.set(self.cfg_data[0]['workingd'])

        self.grid()  # make this be a grid

        ### add the gui elements in here

        ## browse to working directory
        label = Tkinter.Label(self, text="Working Directory", fg="white",bg="blue")
        label.grid(column=0,row=0,columnspan=3,sticky='W')

        self.cwd_entry = Tkinter.Entry(self, width=80, textvariable=self.cwd)
        self.cwd_entry.grid(column=0,row=1,columnspan=2, sticky='W') # http://effbot.org/tkinterbook/entry.htm

        b = Tkinter.Button(self,text=u"Browse", command=self.browse2cwd)
        b.grid(column=2,row=1) 

        toprowscount = 2


        ## command row elements len == len(MyCommands.cmds)
        self.buttons = []
        self.cmd_entries = []
        for rnum, cmd in enumerate(self.cmds):


            label = Tkinter.Label(self, anchor="w",text=cmd['label'], fg="white",bg="blue")
            label.grid(column=0,row=rnum+toprowscount,sticky='EW')

            self.cmd_entries.append( Tkinter.Entry(self, width=60) )
            self.cmd_entries[-1].grid(column=1,row=rnum+toprowscount,sticky='EW'); self.cmd_entries[-1].insert(0, (cmd['cmd']+' '+ cmd['args']))


            b = Tkinter.Button(self,text=u"Ex%s"%(rnum), command=self.bclick(rnum))
            b.grid(column=2,row=rnum+toprowscount) 

            self.buttons.append(b)


        ## Finish up
        self.grid_columnconfigure(0,weight=1) # make resizable
        self.resizable(True,False)            # make resizable ONLY HORIZONTALLY




if __name__ == "__main__":
    app = Theapp(None)
    app.title('Gui Execute Comands')
    app.mainloop()

The Configuration Data File – config.json

Here is the config.json file.

[{
   "programd": "C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand", 
   "commandsf": "C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand\\cmds.json",  
   "configd": "C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand", 
   "workingd": "C:/1d/CrossPlatformPjs/CordovaPjs/cordovaAngular00Pj/cordovaAngular00"
}]

The Initial Command Set – cmds.json

Here is the (INITIAL) cmds.json file

[
  {"cmd": "cordova", "args": "run android", "label": "android build 4 device"}, 
  {"cmd": "cordova", "args": "emulate android", "label": "android build 4 emulation"}, 
  {"cmd": "dir", "args": "*", "label": "dir of working dir"}
]  

A Screenshot of the TKInter Program

Here is a screenshot of the program.

guiExecuteShot

A run log of the program

Here is a run log.

Note: if the user changed the working directory, on exit the new working directory will be saved in the config.json file.

C:\1bat\guiExecuteCommands>guiExecuteCommands.py
browse2cwd:  self.cwd.get(): C:/1d/CrossPlatformPjs/Building Single Page Web Apps with AngularJS PJ
 Volume in drive C is Windows
 Volume Serial Number is F2FB-4810

 Directory of C:\1d\CrossPlatformPjs\Building Single Page Web Apps with AngularJS PJ

12/23/2015  09:58 AM    <DIR>          .
12/23/2015  09:58 AM    <DIR>          ..
12/23/2015  11:11 AM    <DIR>          zetc
               0 File(s)              0 bytes
               3 Dir(s)  900,352,217,088 bytes free
0
self.cwd.get(): C:/1d/CrossPlatformPjs/Building Single Page Web Apps with AngularJS PJ
self.cfg_data: [{u'programd': u'C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand', u'commandsf': u'C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand\\cmds.json', u'configd': u'C:\\1d\\PythonPjs\\GUIpjs\\guiExecuteCommandPj\\guiExecuteCommand', u'workingd': u'C:/1d/CrossPlatformPjs/Building Single Page Web Apps with AngularJS PJ'}]

C:\1bat\guiExecuteCommands>

Show jQuery Client info in web2py View

This web2py View shows jQuery Client Side Info

{{left_sidebar_enabled,right_sidebar_enabled=False,('message' in globals())}}
{{extend 'layout.html'}}

{{block head}}

        $(document).ready(function(){
            $("#width").html($(window).width());
            $("#height").html($(window).height());

        });

{{end}}

{{if 'message' in globals():}}
<h3>{{=message + "hello 3"}}</h3>
<h3>width: <span id="width"></span>    height: <span id="height"></span></h3>
{{pass}}


Get web2py Debugging Info

Get Debugging Info

Here’s a quick way to get debugging info (Mobile or NOT).

from gluon.contrib.user_agent_parser import mobilize
import datetime
@mobilize
def index():
""" Here's an easy web2py debugging action [mobile or NOT] """
response.flash = T("Welcome to web2py!")
m = str(datetime.datetime.now()) +"\n"
m += str(request.user_agent()) +"\n"
m += "\n"
m += "Hi. We have skipped a line."
return dict(message=PRE(T(m)))

Output:
2015-12-03 19:47:23.762934
<Storage {'os': <Storage {'version': 'NT 10.0', 'name': 'Windows'}>, 'is_tablet': False, 'is_mobile': False, 'browser': <Storage {'version': '46.0.2490.86', 'name': 'Chrome'}>}>

Hi. Is next line.