Django intitial setup tips&tricks

Starting up a new Django project might seem a bit repetitive and slow. Setting up all the directives in settings.py takes time that should be used towards building your application.

I needed a deployment methodology that is easy and doesn't require many changes to the settings files or much tinkering.

I have collected a few tricks that i use in my projects to free up some time and make things a lot easier to develop and deploy.

Some of these methodologies only apply to my current set-up which involves managing the application repository with git and using apache with mod_wsgi.

 

  1. Create a git repository (/foo).
  2. Create django project structure (django-admin.py startproject foo).
  3. Create 'extra' directory.
  4. Paste in .gitignore file.
  5. Create virtualenv (virtualenv .)
  6. Go into 'foo' directory.
  7. Copy settings.py to settings_dev.py and settings_live.py.
  8. Delete settings.py file.
  9. Create symbolic link (ln -s settings_dev.py settings.py) so that settings.py points to the dev settings file.
  10. Open up settings_dev.py and add these lines (or replace where applicable):

 

  • ..
  • import os
    import django

    DJANGO_ROOT = os.path.dirname(os.path.realpath(django.__file__))
    SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
  • ..
  • MEDIA_ROOT = os.path.join(SITE_ROOT, 'site_media')
  • ..
  • MEDIA_URL = '/media/'
  • ..
  • ADMIN_MEDIA_PREFIX = 'http://localhost/admin_media/'
  • ..
  • TEMPLATE_DIRS = (
        os.path.join(SITE_ROOT, 'templates')
    )
  •  ..

So now we end up with the following directory structure:

 

  • foo/
  •     .gitignore
  •   bin/
  •   extra/
  •   include/
  •   foo/
  •     __init__.py
  •     settings_dev.py
  •     settings_live.py
  •     manage.py
  •     urls.py
  •     site_media/
  •     templates/
  •   lib/

 

We have now set DJANGO_ROOT and SITE_ROOT to point to the directory where the settings file is located.

We have also set MEDIA_ROOT to point to a directory called 'site_media' within our project root so that our assets can easily be managed by git using the same repository.

The MEDIA_URL variable has to do with how i am using django to develop on my laptop, and the way i have published the project on the production web server.

On my laptop i use the django dev server for the application running on port 9090 (usually) and apache for static files on port 80.

For production i use the apache web server with mod_wsgi and the same apache web server (same machine) for serving static files.

In both scenarios all media files are served from the /media/ URL. This way i don't have to change a thing when going from dev to production.

But, there's a problem here.

  1. Django doesn't serve media files. I have to configure it on dev to do so.
  2. Django shouldn't serve media files in production. So i have to configure apache to do it (without invoking the app [mod_wsgi])

In order to instruct the django dev server to serve media files under MEDIA_URL (/media/) i append the following code to my main urls.py file:

import settings
if settings.DEBUG:
    from django.views.static import serve
    _media_url = settings.MEDIA_URL
    if _media_url.startswith('/'):
        _media_url = _media_url[1:]
        urlpatterns += patterns('',
            (r'^%s(?P<path>.*)$' % _media_url,
            serve,
            {'document_root': settings.MEDIA_ROOT}))
    del(_media_url, serve)

Since i only have 1 urls.py file, this applies both to the dev server and the live production server. Obviously, the production web server cannot serve static files through Django, so this code only applies to instances where DEBUG has been turned on (dev server). It simply adds another urlconf to the existing ones. It invokes `serve` from django.views.static to serve static content under MEDIA_ROOT when MEDIA_URL (/media/) is accessed.

The code above will simply not be used on the production web server. Serving media files is handled by apache.

Here's a typical virtual conf i use for my projects with apache:

<VirtualHost *:80>
        ServerName example.com
        ServerAlias www.example.com

        WSGIDaemonProcess USER-production user=USER group=GROUP threads=10 \n
python-path=/var/www/example.com/foo/lib/python2.5/site-packages

        WSGIProcessGroup GROUP-production
        WSGIScriptAlias / /var/www/example.com/foo/extra/foo.wsgi
        <Directory /var/www/example.com/foo/foo>
            Order deny,allow
            Allow from all
            AllowOverride all
        </Directory>

        Alias /media/ /var/www/example.com/foo/foo/site_media/
        <Location "/media">
            SetHandler None
        </Location>
        ErrorLog /var/log/apache2/error.log
        LogLevel debug
        CustomLog /var/log/apache2/access.log combined
</VirtualHost>

 

This way i can instruct apache to not invoke mod_wsgi when accessing the /media/ URL. Please note that the /media/ URL is set up as an alias to the project site_media directory.

This kind of configuration will allow me to use {{ MEDIA_URL }}css/style.css type syntax on my templates without caring wether this is the dev or the live server.

You will also notice that i set the python-path variable to a path inside my application directory. This is done because i want to separate my django sites using virtualenv.

We are now missing the foo.wsgi script that is used by mod_wsgi as the application starting point. Here it is:

import os
import sys
# put the Django project on sys.path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../")))
os.environ["DJANGO_SETTINGS_MODULE"] = "foo.settings"
from django.core.handlers.wsgi import WSGIHandler
application = WSGIHandler()

 

As simple as that. Since this script is ran from within the extra/ directory, '../' is appended to the path. This way all my django scripts can use the notation: foo.app.models to reference models/forms/methods etc.

Now on to the virtualenv setup.

As it is, the production server has no clue how to use django. It has not been installed yet (all the pre-requisites have though).

Seeing as i want to use virtualenv, i will not be installing django system-wide. Instead i am going to dowload the latest official release and install it for this django project alone.

I usually download and unzip Django releases in /opt. After the latest release has been unzipped, i have to somehow install it for this project. We will do this by going into foo/lib/python2.5/site-packages/ and create a symbolic link to the newly unzipped Django folder in /opt. We will name this link "django".

So, within the above directory we issue the command: ln -s /opt/Django-1.2.5/django django

Now, we can go back into our project folder (/var/www/example.com/foo/foo) and verify that django is available:

 

../bin/python manage.py shell
Python 2.5.2 (r252:60911, Jan 24 2010, 17:44:40) 
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> import django
>>> django
<module 'django' from '/var/www/example.com/foo/lib/python2.5/site- \n
packages/django/__init__.py'>

 

Django custom format files

I have recently been searching for a way to output numbers (currency) using the django template that will obey certain locale rules without resorting to custom filters and tags.

I found out about the Django format files module: http://docs.djangoproject.com/en/1.2/topics/i18n/localization/#creating-custom-format-files

Using this module i am able to output correctly formatted currency numbers according to the current locale set by the user/system.

 

That is, until i ran into a bit of trouble.

One thing that is not directly apparent is that this will eventually cause troubles when outputting number greater that 1000.

If you are using URLconfs to parse for whole numbers (blog posts, articles etc) and try to generate a link in a Django template using the object's id like this: link/to/a/post/{{ obj.id }}/ the id generated will be formatted according to your preferences in the format files. This will either include a comma or a dot as the thousand separator and it will break your URLconf (it won't match \d+).

This is a problem because it wasn't directly apparent to me when i started using the format files. My object count had to go over 1000 for me to be alerted to that particular problem.

One way to get around this is to mark the id as safe when inserting into the template like this: {{ obj.id|safe }}.

This will forego all processing on obj.id and it will output a whole number without the thousand operator defined in the format files.

Περί απεργειών ο λόγος

Σήμερα είναι μία ακόμη ιδιαίτερα περίφανη μέρα για την πατρίδα μας. Η Ελλάδα απεργεί κυρίες και κύριοι. Σήμερα η Zimbabwe έχει παράγει μεγαλύτερο έργο απο την Ελλάδα.

Και φυσικά οι απεργείες είναι αδιαμφισβήτητο δικαίωμα του Έλληνα πολίτη (για κάποιο λόγο που μου ξεφεύγει αυτή την στιγμή!).


Κάποια στιγμή πέρυσι που είχαν ξαναγίνει πανελλαδικές απεργείες ΓΣΕΕ-ΑΔΕΔΥ, συζητούσα με έναν φίλο μου στην Αγγλία και προσπαθούσα να του εξηγήσω ότι την συγγεκριμένη χρονική στιγμή η Ελλάδα σαν σύνολο απεργούσε και ότι δέν υπήρχε εθνικό έργό για μία ή και για πολλές φορές 2 μέρες στην σειρά. Όσο και να του το εξηγούσα δέν το καταλάβαινε.

Και πώς να το καταλάβει, Άγγλος άνθρωπος, που έχει συνιθίσει να δουλεύει από τα 16 του, και ήταν οικονομικά ανεξάρτητος απο τα 18 του χωρίς να περιμένει μερικούς χοντρούς κυρίους που τρέχουνε τα σωμματεία και πρόσκυνται σε συγγεκριμένα πολιτικά κόμματα (και φυσικά εξυπηρετούν συγγεκριμένα πολιτικά συμφέροντα), να τον ταϊσουνε ψωμάκι!

Η μεγαλύτερη αρετή του νεοέλληνα είναι να διαιωνίζει καταστάσεις (procrastination). Το κάνουμε καλά. Το κάνουμε εδώ και καιρό. Καί σε προσωπικό επίπεδο αλλά καί σε εθνικό. Έλα όμως τώρα που τα πήρε χαμπάρι η Ευρωπαϊκή Ένωση και μας έκοψε τον τσαμπουκά! Και είμαστε αυτή την στιγμή σάν το 13χρονο που πείραζε τα άλλα παιδάκια και το έχει βάλει η μαμά του τιμωρία! Κομμένος ο τσαμπουκάς (γιατί άλλωστε δέν μας συμφέρει πλέον).

Αλλά και πάλι βρίσκουμε δικαιολογίες για να μήν πληρώσουμε εμείς τα σπασμένα. Γιατί άλλωστε, σε αυτή την χώρα φταίνε πάντα οι άλλοι.

Απεργείες απο εδώ, πορείες απο την άλλη. Δέν μπορείς να βρείς βεντζίνη, αλλα ούτε μπορείς να πάρεις τα τραίνα. Εάν δέν έχεις προσωπικό ελικόπτερο αυτή την εποχή είναι άσχημα τα πράγματα!

Έτσι όμως έχει συνιθίσει ο Έλληνας. Να δουλεύει (λέμε τώρα) μία ζωή στο δημόσιο, να μήν έχει κανένα όνειρο πλέον αυτού, και να περιμένει την σύνταξη για να αρχίσει να ζεί!!! Πότε γίναμε ένα έθνος ζωντανών-νεκρών;

Αυτό που χρειάζεται είναι μία (μικρή) έξαρση εθνικού φρονήματος (βλέπε Γερμανοί). Πρέπει να σταματήσουμε να περιμένουμε τρίτους που μας υπόσχωνται μία καλύτερη ζωή και να αρχίσουμε να δουλεύουμε για να βγάλουμε τα σπασμένα για να πάει η Ελλάδα μπροστά.

Ξυπνάτε γιατί χανόμαστε!

Μαμά Ελλάδα

Σήμερα είπα να εκμεταλευτώ την ολιγοήμερη άδειά μου (είμαι στρατιώτης στο σώμα εφοδιασμού-μεταφορών για όσους δεν το ξέρανε) για να πάω να παρακολουθήσω μία θεατρική παράσταση απο τους Abovo.

Abovo

Το έργο ονομάζεται "Μεγάλη Ελλάδα 2" και μπορείτε να πάτε να την δείτε και εσείς στο θέατρο του 'Ηλιου, θέατρο ΧΩΡΑ.

Η παράσταση είνα μία διακωμώδηση της μοντέρνας Ελλάδας μέσα απο το τηλεσκόπιο των μελών του Abovo. Οι Abovo καταφέρνουνε να περιγράψουνε την κατάσταση της Ελλάδας, την διαφθορά και την ιδεολογία του μοντέρνου Έλληνα χωρίς τον λαϊκίστικο τόνο μιάς επιθεώρησης.

Η ενέργεια και η φρεσκάδα τους δίνει έναν πολύ ελαφρό τόνο στα πολύ σοβαρά θέματα τα οποία διακωμωδούν. Η παράσταση είναι κυρίως κωμωδία αλλα έχει και μερικά κωμικοτραγικά στοιχεία τα οποία δίνουν ιδιαίτερη βαρύτητα σε ορισμένα θέματα όπως η διαφθορά κ.α.

Απ'ότι καταλαβαίνω οι Abovo ετοιμάζουνε και σειρά στην Ελληνική τηλεόραση την οποία περιμένω ανυπόμονα. Θα σας συνιστούσα να δείτε αυτήν την υπέροχη παράσταση και εσείς.

Ιδού και μερικά links:

Το site των Αbovo
Video απο το "Μεγάλη Ελλάδα" στο Youtube

Deploying Django

I recently decided to see what the fuss is about pip/fabric/virtualenv and mod_wsgi. I have come across these terms before, i knew what they were all about but never had time to test them for myself.

After reading an article by Jon Atkinson (http://jonatkinson.co.uk/django-project-base/) i decided to look into all this.

I have been running all my django apps using my trusted old friend mod_python. While i am also running memcached i felt that i wasn't getting the performance that other django sites have. So i decided to ditch mod_python and try mod_wsgi out.

The changes needed to go from mod_python to mod_wsgi are minimal and quite easy to perform. Immediately after i switched to mod_wsgi i saw a big performance increase. My apps stopped feeling slugish, and memory consumption went down significantly.

My munin stats seemed to verify those feelings. I am not going to go into specifics (apache processes running under different users etc) but i have to say that i am quite impressed with it!

The next task was to look into automatic set-up and deployment using fabric and pip, along with vitualenv.
Fabric makes it easy for admins to set up and deploy/update their sites by automating the whole process using a simple script.

I am able to set up all the prerequisites (apache, mysql, python, python-mysql, PIL etc) with a single command from my local machine. I am then able to configure apache, create a new virtualhost, and upload the new version of my app using git/svn etc (anything really).

I have been performing these tasks manually for so long and they were getting very boring. While there will always be the need to do specific things manually (that's why you're an admin), fabric will save you a lot of time.

Now on to pip.

pip is a program that installs python programs. According to their website "It is a replacement for easy_install.".
Using pip along with virtualenv gives you the ability to install localized versions of python modules (PIL etc). This is *very* useful since different projects on the same server might require different versions of the same library.

To conclude with, all these great apps will make your life easier. Deployment happens faster, and can be tracked if you're using a version control system. Once you come up with your own scripts setup and deployment will be a breeze.

I would like to know what you think about this method. Have you used it before? Have you got any more tips? Make sure you leave a comment.

LINKS