Short Django Tutorial Notes

July 24th, 2011 § 1 comment § permalink

Some condensed notes on the Django tutorial (Django 1.3) This is just a short self-reference (or maybe a 2-minute overview), not an actual tutorial.

Database

Create / update database

python manage.py syncdb

Models

Models define how data is stored. Create a model by inheriting from django.db.models.Model

from django.db import models
 
class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    choice = models.CharField(max_length=200)
    votes = models.IntegerField()
    def __unicode__(self):
        return self.choice

App

An “app” is simply a directory with an __init__.py file and other python files. (An “app” is more commonly known in other languages as a “package”.)

The INSTALLED_APPS variable in settings.py tells Django which apps to use.

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'polls'
)

Make sure your app directory is on your Python path.

Re-run python manage.py syncdb after making changes to the INSTALLED_APPS.

URLs

The variable urlpatterns tells Django which Python code to run (which view to use) based on the url path.

from django.conf.urls.defaults import patterns, include, url
from django.contrib import admin
admin.autodiscover()
 
urlpatterns = patterns('',
   (r'^polls/$', 'polls.views.index'),
   (r'^polls/(?P
<poll_id>\d+)/$', 'polls.views.detail'),
   url(r'^admin/', include(admin.site.urls)),
)

The ROOT_URLCONF variable in settings.py tells Django where to find the module-level variable urlpatterns. E.g. if urlpatterns is defined in mysite/urls.py, the settings.py file should have

ROOT_URLCONF = 'mysite.urls'

View

The code used to generate a page is called a view. A view is a Python function which returns a web page. Example index() view in polls/views.py

from django.template import Context, loader
from polls.models import Poll
from django.http import HttpResponse
 
def index(request):
    latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
    t = loader.get_template('polls/index.html')
    c = Context({
        'latest_poll_list': latest_poll_list,
    })
    return HttpResponse(t.render(c))

The urlpatterns tells Django which view to use based on the url. For example, the urlpatterns line

   (r'^polls/$', 'polls.views.index'),

tells Django that the url http://site.com/polls is created by the index() function in polls/views.py.

render_to_response is a common shortcut for creating views. Equivalent view using render_to_response

from django.shortcuts import render_to_response
from polls.models import Poll
 
def index(request):
    latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
    return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})

Often views need to respond to a request. Templates use the {% csrf_token %} to prevent “Cross Site Request Forgeries”, and the view uses a django.template.RequestContext

from django.template import RequestContext
# ...
def detail(request, poll_id):
    p = get_object_or_404(Poll, pk=poll_id)
    return render_to_response('polls/detail.html', {'poll': p},
                               context_instance=RequestContext(request))

Template

A Django template is a HTML skeleton with special Django tags which tell the Django view where to fill in data. Example template polls/index.html

{% if latest_poll_list %}
<ul>
    {% for poll in latest_poll_list %}
<li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>
 
    {% endfor %}
    </ul>
 
{% else %}
    <p>No polls are available.</p>
{% endif %}

Admin Interface

Register apps with Django’s admin interface

from polls.models import Poll
from django.contrib import admin
 
class PollAdmin(admin.ModelAdmin):
    fields = ['pub_date', 'question']
 
admin.site.register(Poll, PollAdmin)

Generic Views

There’s generic views which means that you don’t have to write a view function; you use django.views.generic to generate a simple view.

from django.conf.urls.defaults import patterns, include, url
from django.views.generic import DetailView, ListView
from polls.models import Poll
 
urlpatterns = patterns('',
    (r'^$',
        ListView.as_view(
            queryset=Poll.objects.order_by('-pub_date')[:5],
            context_object_name='latest_poll_list',
            template_name='polls/index.html')),
    (r'^(?P
<pk>\d+)/$',
        DetailView.as_view(
            model=Poll,
            template_name='polls/detail.html')),
    url(r'^(?P
<pk>\d+)/results/$',
        DetailView.as_view(
            model=Poll,
            template_name='polls/results.html'),
        name='poll_results'),
    (r'^(?P
<poll_id>\d+)/vote/$', 'polls.views.vote'),
)

Installing Mezzanine (Django based CMS) on Dreamhost via virtualenv

July 20th, 2011 § 3 comments § permalink

Here’s some notes for installing Mezzanine on Dreamhost using virtualenv. This can be useful for installing on any server where you don’t have permissions to install python packages normally. There’s also notes here for how to set up Passenger to serve your site via Apache.

In Dreamhost panel, setup site for use with Passenger & ssh

Ssh into your Dreamhost server

Setup a Python virtualenv so you can install your own Python packages. Check the virtualenv pypi page for the latest virtualenv version (currently 1.6.3).

wget http://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.6.3.tar.gz
tar xzf virtualenv-1.6.3.tar.gz
python virtualenv-1.6.3/virtualenv.py $HOME/local
rm -rf virtualenv*
export PATH=$HOME/local/bin:$PATH

You probably want to add $HOME/local/bin to your path permanently. Add the export line to your ~/.bashrc file:

export PATH=$HOME/local/bin:$PATH

To make sure that you are using the virtualenv python, check that which python returns /home/youruser/local/bin/python and NOT /usr/bin/python.

Now you can install some Python packages

pip install --upgrade django mezzanine south paste

Create a mezzanine project

cd ~/site.com
# Name this project whatever you like.  I will use "mez"
mezzanine-project mez

Edit your settings in mez/local_settings.py. I will leave the sqlite database for testing. You could should probably create a mysql database for a real site though. Add these lines so Django knows where files are.

TIME_ZONE = 'America/Los_Angeles'
APP_URL = 'http://site.com'
## Note the leading and trailing slash here
#ADMIN_MEDIA_PREFIX = '/admin_media/'
#MEDIA_ROOT= '/home/youruser/site.com/mez/site_media/'
#MEDIA_URL = 'http://site.com/site_media'

Setup your site with Passenger by creating a ~/site.com/passenger_wsgi.py file with the following:

import sys,os
# Force Passenger to run our virtualenv python
INTERP = "/home/youruser/local/bin/python"
if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)
# Setup paths and environment variables
sys.path.append("/home/youruser/site.com")
sys.path.append("/home/youruser/site.com/mez")
os.environ['DJANGO_SETTINGS_MODULE'] = 'mez.settings'
# Set the application
import django.core.handlers.wsgi
from paste.exceptions.errormiddleware import ErrorMiddleware
application = django.core.handlers.wsgi.WSGIHandler()
# Use paste to display errors
application = ErrorMiddleware(application, debug=True)

Now setup the static files

ln -s ~/site.com/mez/site_media ~/site.com/public/site_media

Setup the database

cd ~/site.com/mez
python manage.py syncdb
# I think I initially had some errors running migrate, 
# but it worked the second time running migrate
python manage.py migrate

Restart the web server. Ordinarily you might do sudo /etc/init.d/apache2 restart. On Dreamhost you do this by touching tmp/restart.txt. (If the tmp directory doesn’t exist, mkdir ~/site.com/tmp)

touch ~/site.com/tmp/restart.txt

That should be it. Check to see if your site is up and running.

TODO’s: setup mysql, customize theme, etc

There’s alternative ways to handle the static files. The package django-staticfiles might be better? I haven’t tried it.

Python call easy_install within a Python session

February 17th, 2011 § 0 comments § permalink

Thanks stack overflow

from setuptools.command import easy_install
easy_install.main( ["-U","py2app"] )

Python Getters and Setters

February 1st, 2011 § 0 comments § permalink

A quick note on defining getters and setters using decorators for Python 2.6+

#Must inherit from object
#class C: won't work.
class C(object):
    # Define getter for x
    #@x.getter doesn't work because self.x is not defined yet  :(
    @property
    def x(self):
        return self._x
 
    # Define setter for x
    @x.setter
    def x(self, value):
        self._x = value
 
    # Define deleter for x
    @x.deleter
    def x(self):
        del self._x
 
class D(C):
    @C.x.getter
    def x(self):
        return self._x * 2
 
    @x.setter
    def x(self, value):
        self._x = value / 2

code stolen from the What’s new in 2.6 doc

Editorializing: I don’t like the asymmetry of defining the getter and the setter. It would be better if @x.getter would work for the setter instead of using @property for the getter. But I guess it’s better than using x=property(x_getter, x_setter). Work on it, Guido.

Python: Create directory

January 21st, 2011 § 0 comments § permalink

Simple Python snippet which creates a directory if it doesn’t exist.

#! /usr/bin/env python
import os
 
# create directory "mydir" if it doesn't exist already
os.path.exists("mydir") or os.mkdir("mydir")

Python Gripes

January 16th, 2011 § 0 comments § permalink

It seems like a real object oriented language shouldn’t require “self” as the first argument to all its class methods. It reminds me of Matlab’s hackish inefficient classes. Down with the explicit self!

Not having to type semicolons at the end of lines is nice, but needing to type colons at the end of function definitions and if statements is not. I always forget it. And when I put it in, using the colon makes me feel like I’m only using the left curly brace; like something is missing.

class Moose
    def __init__()
        print('moo')

/rant

Python ChIP-seq BED file reader

January 15th, 2011 § 0 comments § permalink

A simple BED file reader in Python.

import csv
class CommentedFileReader:
    """
    Helper class for file reading.
    Skips lines starting with '#'
 
    tsv_file = csv.reader(CommentedFileReader("inputfile.txt"),
                      delimiter='\t')
    for row in tsv_file:
        print row[2] # prints column 3 of each line
    """
    def __init__(self, f, commentstring="#"):
        self.f = open(f, 'rU')
        self.commentstring = commentstring
    def next(self):
        line = self.f.next()
        while line.startswith(self.commentstring):
            line = self.f.next()
        return line
    def __iter__(self):
        return self
 
csv.register_dialect('bed', delimiter = '\t', 
                     quoting = csv.QUOTE_NONE,
                     skipinitialspace = True)
 
class BEDReader(csv.DictReader):
    """
    Read BED files into a DictReader.
    See BEDReader.FIELDS for field names
 
    Example:
        bed = BEDReader("file.bed")
        for line in bed:
            # print the chromStart
            print(line['chromStart'])
    """
    FIELDS = ('chrom', 'chromStart', 'chromEnd', 
              'name', 'score', 'strand',
              'thickStart', 'thickEnd',
              'itemRgb', 
              'blockCount', 'blockSizes', 'blockStarts')
 
    def __init__(self, filename):
        csv.DictReader.__init__(self, CommentedFileReader(filename), dialect='bed', 
                                fieldnames=self.FIELDS)
 
if __name__ == "__main__":
    bed = BEDReader("data.txt")
    for line in bed:
        print(line['chromStart'])

Python: matplotlib plotting with customized axes

October 20th, 2010 § 0 comments § permalink

I don’t like the Matlab plot axes where you are forced to have a box around your figure. By default, Python’s matplotlib plots like Matlab, but you can customize the axes to your liking.

matplotlib plot

Modified from the matplotlib spine demo

import matplotlib.pyplot as plt
import numpy as np
 
fig = plt.figure(facecolor='white')
x = np.linspace(0,2*np.pi,100)
y = 2*np.sin(x)
 
ax = fig.add_subplot(1,1,1, aspect='equal')
ax.set_title(r'$y=\sin(t)$')
ax.plot(x,y)
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.autoscale_view(tight=True)
ax.set_ylim(-2.5,2.5)
ax.set_xlim((0,2*np.pi))
ax.set_xticks([0,np.pi,2*np.pi])
ax.set_xticklabels(['', r'$\pi$', r'$2\pi$'])
ax.text(2*np.pi + .1, -.2, r'$t$') # Manually adjusted
 
plt.savefig('plot.pdf')
plt.show()