Django

Python Web/Database Applications

Web/Database applications have to do with responding to a browser request, processing information (from database and other), and generating a dynamic response based on the computation. There are three parts identified in this operation: Every Web/Database application has these aspects. What a web framework does is provide the structure for creating such application in which the M-V-C components are abstract and independent of each other as much as possible. The outcome is that the web framework structure provides: A language like Php is well suited to serving both roles: the controller classes and the template language. In contrast, Python is very well-suited to being the creating controller classes, but poorly suited to serving as a template language. There are many Python-based web frameworks such as Django, Zope2, CherryPy. All use Python to define the controller classes and support a separate template script language to generate the views.

Django

Install Django and the Python MySQL package (we did it already):
$ sudo apt-get install python-django python-pymysql
Although we will make use of PyDev as the IDE of choice for creating Django applications, there no absolute need to do so. Django provides shell-based tools for creating and manipulating its projects and any editor will work fine. PyDev simply offers extra support to make things convenient, in particular, running the development web server.

The Django site provides excellent documentation and tutorials:
https://docs.djangoproject.com/en/1.8/
The 6-part tutorial on Django is a recommended way to learn it.

This document is written for Django version 1.8. When you look for Django documentation, make sure that you the docs version matches the version you're using because there are significant version differences. Verify the version you are using by running:
$ python -c "import django; print(django.get_version())"

Eclipse PyDev Re-configuration

Because of the Django Python software additions, we need to reset PyDev's PYTHONPATH environment variable. Go to Window ⇾ Preferences and select
PyDev ⇾ Interpreters ⇾ Python Interpreter
Click Apply to activate. A popup window asks for:
Select interpreters to be restored
 python (/usr/bin/python)

Click OK to rebuild and then OK to leave.

Create a Django Project

Django considers a project to be a "site," suggesting that it is the basis of one or more possibly-related web apps. Our site name is "appsite" to avoid conflict with "mysite" used in the Django tutorial. Create the site in Eclipse as follows:

Initial layout and configuration

The files you'll see within the Django appsite project created are:
appsite/
  manage.py
  appsite/
    __init__.py
    settings.py
    urls.py
    wsgi.py
The presence of __init__.py in the internal appsite indicates that the directory is a Python package.

Project creation in shell

This subsection is just for reference. You don't have to do it if you've already created the project.

As we mentioned earlier, everything done by PyDev can be done using only shell commands. The advantage to this presentation is that it is IDE-independent. The shell equivalent of creating the Django project is:
$ cd ~/workspace
$ django-admin startproject appsite  
$ cd appsite  
--- do everything else from here ----

Importing project code into Eclipse

This subsection is just for reference. You don't have to do it if your going along in Eclipse.

If you are working on a Django project through the shell, at any point you can realize your project afterwards as a PyDev/Django project in Eclipse, although it is less transparent than it should be. Here are the steps:

Change these timezone features

Python will want to use UTC to set time stamps. We want local time, so make these changes (we'll use it later):

appsite/appsite/settings.py
TIMEZONE = "America/New_York"
...
USE_TZ = False
Having to make both changes seems odd, but you have to.

Run the development server

Django provides a fully-compliant HTTP 1.1 web server which is used to run its applications.

To run this server from PyDev, simply click on the appsite project line and select
Run As ⇾ 1 PyDev: Django
The Console window you should see information:
...
Django version 1.8.7, using settings 'appsite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
As suggested by the message, open a web browser to the URL to see the welcome message:
http://127.0.0.1:8000

Run the development server from the shell

Again, this subsection is just for reference.

The shell equivalent of what we have just done is:
--- in ~/workspace/appsite ----
$ python manage.py runserver
Running the server will block the shell. One of the issues of running it this way is that for some changes you make, you have to stop (Control-C) and restart the server to pick them up. In contrast, when run through PyDev, the server is restarted as necessary.

Create the blog app

The PyDev project structure provides menu-driven capabilities to do the various creations and modifications to the project structure through a dedicated Django menu accessible from the project.

Right-click on the project, select
Django ⇾ Create application (manage.py startapp)
This brings up a dialog window:
App Name
Name of the django app to be created:
blog
Name cannot be empty
Click OK.

The newly created files and folders constitute this Python package:
blog/
  __init__.py
  admin.py
  models.py
  tests.py
  views.py
This package is at the same level as the appsite package, the full Django project structure looks like this:
appsite/
  manage.py
  appsite/
    ...
  blog/
    ...

App creation from the shell

Again, this is an equivalent, which has already been done. To create the blog app run this:
--- in ~/workspace/appsite ----
$ python manage.py startapp blog
If you're working in Eclipse as well, refresh the appsite project to pick up the additions.

Create the initial blog app features

Edit blog/views.py, adding this initial content after the "Create your views here" comment line:

blog/views.py (appended)
from django.http import HttpResponse
 
def index(request):
    return HttpResponse("The blog index.")
select
Create a new file. Then enter this code:

blog/urls.py
from django.conf.urls import url
 
from . import views   # or: from blog import views
 
urlpatterns = [
    url(r'^$', views.index),
]
 
select
Edit appsite/urls.py. Look for the urlpatterns definition make this addition:

appsite/urls.py
urlpatterns = [
    ...
    url(r'^blog/', include('blog.urls')),  # add this line
]
This says that any URL starting with "blog" will be resolved in the blog.urls module. Observe the outcome:
http://127.0.0.1:8000/blog

Apache site access via ModWSGI

The aim of Apache Mod WSGI is to provide a simple module which can host any Python application which supports the Python WSGI interface. You should not use this WSGI access for site development. Keep the local site on port 8000; Apache must be reloaded to pick up any changes.

If you look at Django/WSGI documentation on the web, the docs indicate that the Python site is deployed in a virtual environment separate from the Python environment supplied by the operating system. This is possibly a better approach to avoid conflict with multiple WSGI sites, but it is unnecessary for our purposes.

Install (and enable) the relevant Apache modules
$ sudo apt-get install libapache2-mod-wsgi
We also need to enable the HTTP proxy_http module Each Django project (site) that you want to make public should have its own Apache virtual host entry. We can easily create our own different hosts by using the loopback IP addresses 127.0.x.y with corresponding apache virtual host sites.

Create an entry in /etc/hosts:
127.0.1.2	appsite
Create the name virtual host site:

/etc/apache2/sites-available/appsite.conf
<VirtualHost appsite:80>
  WSGIScriptAlias / /home/LOGIN/workspace/appsite/appsite/wsgi.py
 
  # This code is needed when you have multiple wsgi sites
  # The processGroup name choice must be different for each website.
  WSGIDaemonProcess appsite python-path=/home/LOGIN/workspace/appsite
  WSGIProcessGroup appsite
 
  <Files wsgi.py>
    Require all granted
  </Files>
 
  # needed to realize the "/static" URL when appsite is used as host
  Alias /static /var/www/html/static
 
  # these are standard logging directives
  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
select
Enable the newly-created site by:
$ sudo a2ensite appsite
and restart Apache to pick it up:
$ sudo service apache2 reload
With this in place you can test:
http://appsite/blog

Picking up changes

Make a simple change to the reponse generated in the blog/views.py file.

blog/views.py
from django.http import HttpResponse
 
def index(request):
    return HttpResponse("The blog index, modified.")
select
Then compare the development and Apache sites:
http://localhost:8000/blog
http://appsite/blog
You'll see that the development site has picked up the changes, but the Apache site has not. Then reload Apache:
$ sudo service apache2 reload
Now you'll see that the Apache site has picked up the changes.

Make /blog externally accessible

You want the proxy_http module installed:
$ sudo a2enmod proxy_http
Then modify the Apache default HTTP site:

/etc/apache2/sites-enabled/000-default.conf
<VirtualHost *:80>
  ProxyPreserveHost On
  ProxyPass  /blog   http://appsite/blog
  ...
</VirtualHost>
Reload Apache to pick up all changes:
$ sudo service apache2 reload
Afterwards, you can use:
http://localhost/blog
http://MACHINE/blog
With the latter one, you can also access this /blog site from, say, a taz client external to your machine.

Tunnel access

If you're accessing MACHINE through the taz tunnel, this will also work:
http://localhost:2003/blog

Simplify access to test URLs

I find it useful to have a web page with a listing of test URL hyperlinks instead of keying them into the browser location. Create the Php file in your ~/public_html directory:

test_urls.php
<?php
$urls = [
  'http://localhost:8000/blog',
  'http://appsite/blog',
  'http://localhost/blog',
  // ...
];
?>
<!DOCTYPE html>
<html>
<head>
  <title>TEST URLS</title>
  <style>
  li { margin: 5px 0; }
  </style>
</head>
<body>
  <h3>TEST URLS</h3>
  <ul>
    <?php foreach ($urls as $url): ?>
    <li>
    <a href="<?php echo $url?>"><?php echo $url?></a>
    </li>
    <?php endforeach ?>
  </ul>
</body>
</html>
select
Access it via:
http://localhost/~LOGIN/test_urls.php
Then save it as a bookmark, say on your bookmarks toolbar.


© Robert M. Kline