django standalone scripts

Standalone scripts and cron jobs are integral part of any significantly complex web based application. We use them in our applications for health monitoring, mails sending, computing scores and ratings, deferred tasks and job queues such as video processing etc.

To make a python script work which uses django's functionality, you need to have the required environment variables set: your application's path in your PYTHON path and name of the settings module in DJANGO_SETTINGS_MODULE. If you are using Unix, you can set these in your bash_profile so that each time you log in, the environment variables are already set.

For instance, if your project's name is myproject, then add these lines (with appropriate changes) in ~/.bash_profile file:


export PYTHONPATH="/home/path/to/myproj/"
export DJANGO_SETTINGS_MODULE="myproj.settings"

Now you can write and execute a python script which imports models and views of myproj.

CronJobs using the django models or views also need these environment variables which can be set at the top of the crontab file. Open the crontab file using this command on shell:


$crontab -e # Edit the crontab file

Put these lines at the top to pass required environment variables to any subsequent cronjobs


PYTHONPATH=/home/path/to/myproj/
DJANGO_SETTINGS_MODULE=myproj.settings

If you use webmin for scheduling cronjobs, you can create environment variables from from the menu.

Django Subdomains

We have added a new feature at See'n'Report. It now provides each user with a personal sub-domain URL. The URL maintains user's profile which lists all the photo reports submitted by the user. For example my See'n'Report profile URL is http://sharjeel.seenreport.com/ .

Adding support for sub-domains in Django is simple but has a few catches. It took me quite some time to get everything working.

The following links provide a quick way to make sub-domains:

rossp.org - Using Subdomains with Django
Django Ticket #5022 - Proposed middleware: SubdomainURLsMiddleware

The summary of above links is that you have to put a wildcard entry in your domain DNS so that all your subdomains resolve to the IP on which your site is hosted. Then make sure apache handles all the requests to sub-domains; again using a wildcard in apache's configuration. Then write a middleware which checks the subdomain in request's HTTP Host header and processes it accordingly by either loading a customized URLs pattern or by handling the request with a view with appropriate logic.

This worked well for me and I was quickly able to make the changes so that http://www.seenreport.com/user/sharjeel was available at http://sharjeel.seenreport.com/.>

There were a few little problems:

Firstly, sessions did not work across the subdomains. If I were logged in www.seenreport.com, I wouldn't be logged in at sharjeel.seenreport.com.  This was solved by using setting the SESSION_COOKIE_DOMAIN variable in settings.py:

 SESSION_COOKIE_DOMAIN = '.seenreport.com' if not DEBUG else '.localhost'

Secondly, all the main navigation links (login, register etc.) which were written as relative links were now pointing to sharjeel.seenreport.com instead of www.seenreport.com. For instance the login on my profile page became sharjeel.seenreport.com/login instead of www.seenreport.com/login.>

I could have hardcoded "www.seenreport.com" with these links to make them absolute URLs but that would have been bad in terms of maintainability. It requires an if-else logic for each link so that it renders accordingly on dev/test machines and the production machine.

I used <base> tag with href="http://www.seenreport.com/" (for production, and localhost for dev) to make the navigation links relative to main domain.  This also changed the profile links. However, in our case, profile links are very few so adding hardcoded absolute URLs alongwith some {{ if }}  {{ else }} is viable.

Using base-href everything became well except one. Ajax calls didn't work now. When using <base> tag, the URLs of your ajax calls become relative to href. In this case when an ajax call is made, a domain other than your current one is contacted, which is disallowed by the browser and following exception is raised:

"Access to restricted URI denied" code: "1012"

To overcome this, I appended following with each ajax call's URL:

location.<span style="color: #006600;">protocol</span> + <span style="color: #3366cc;">'//'</span> + location.<span style="color: #006600;">host</span> + original_url ...
 

This made all the ajax calls relative to the current subdomain and made everything work perfectly. Took me quite some time to figure out :)