Friday, December 28, 2007

HowTo: Django Dev Environment on MacOSX Tiger using MacPorts

The Mac uses Python in the OS itself, so messing with the system Python can be risky, and Apple has a bad reputation for compliance with the official Python, because the earlier versions of OSX shipped with broken Python installations, and even recent versions of OSX ship with modified versions of Python.

MacPorts can give you a consistent django dev environment with easy upgrades, but you have to be conscious of which Python you are calling and make sure your PATH variables are set correctly when making scripts, using IDEs, and so on. MacPorts offers a django port, so you could feasibly set up everything through MacPorts, but I set up django with subversion here.

MacPorts
  1. Install MacPorts from the Mac OSX package.
Python Environment and Postgresql
  1. Macports treats each piece of software as a "port," and it downloads the source, compiles, and then installs the software for you. MacPorts also installs dependencies for you, so if you tell MacPorts to install port C, which is dependent on A and B, MacPorts will install A, B, and C.
  2. In order to make sure that your MacPorts has the latest info, update it with:
    sudo port sync
  3. For Django, we need a DBMS, and I choose Postgresql. We need psycopg to link it to Python, so let's first find out which postgresql, python, and psycopg ports are available:
    sudo port search postgresql
    sudo port search python
    sudo port search psycopg
  4. A little research reveals that, as of this writing, the differences in Python 2.4 and Python 2.5 have necessitated that the MacPorts project separate related ports into those beginning 'py-' for Python 2.4 and 'py24-' for Python 2.5. So since I want to use Python 2.5 with Postgresql, I will need to use py25-psycopg2.
  5. The port maintainer decides the dependencies of the port she maintains, so the dependencies of py25-psycopg2 will determine the version of Postgresql to be installed:
    sudo port deps py25-psycopg2
  6. Though postgresql82 is the newest version, py25-psycopg2 depends on postgresql81, so that is the one I will go with.
  7. So let's start with the database server:
    sudo port install postgresql81 postgresql81-server
  8. Now we need to install Python 2.5:
    sudo port install python25
  9. And now the library that allows Python and Postgresql to communicate:
    sudo port install py25-psycopg2
  10. Technically, this is the minimal set of parts needed for django, but the MacPorts version of Python includes only the essentials, leaving it to the user to add modules, and some of these excluded modules are needed to really use Django. First install py25-hashlib to accommodate Django's authentication module:
    sudo port install py25-hashlib
  11. Next, install py25-readline if you want the interactive interpreter to be usable at all (backspace, delete, etc.):
    sudo port install py25-readline
  12. Another recommendation is to install iPython, which is an enhanced Python interactive shell. While I would not bother if I had to manually configure Django to work with iPython, I recommend it here because (1) iPython is multi-platform and (2) Django was modified to call iPython, if found, and only if not found to call the regular interactive shell.
  13. Then install other modules you might need:
    sudo port install py25-bz2 py25-zlib py25-crypto py25-chardet py25-dateutil py25-socket-ssl
  14. Though postgresql is installed, it is not really set up yet. For the sake of easy management, I want to keep all user databases in /Users/DB/postgresql, so first make that dir:
    sudo mkdir /Users/DB/postgresql
  15. Now we go to Netinfo Manager to find out what user (and group) MacPorts installed for postgresql. It should be user postgres, but my install resulted in the following, so I give it a password :
    username: postgres81
    group: postgres
    passwd: agoodpassword
  16. Make PostgreSQL binaries available to user by adding to PATH in ~/.profile:
    echo 'export PATH=$PATH:/opt/local/lib/postgresql81/bin' >> ~/.profile
  17. Since PostgreSQL will run under postgres81 user, we need to make it own the postgresql directory:
    sudo chown -R postgres81:postgres /Users/DB/postgresql
  18. Initialize the PostgreSQL master database. We are starting PostgreSQL as user postgres81, so we use sudo to elevate privileges; use su to assume the user we want, then use -c to tell su to execute a command as user postgres81:
    sudo su postgres81 -c "initdb -D /Users/DB/postgresql"
  19. Add postgresql start and stop commands to profile:
    alias pgstart="sudo su postgres81 -c 'pg_ctl -D /Users/DB/postgresql -l /Users/DB/postgresql/logfile start'"
    alias pgstop="sudo su postgres81 -c 'pg_ctl -D /Users/DB/postgresql stop -m fast'"
    alias pgstatus="sudo su postgres81 -c 'pg_ctl status -D /Users/DB/postgresql'"
  20. Now logout and log back in, then create a role (user) in postgres with the same name as the login who will use it:
    sudo su postgres81
    createuser -s -P -l
  21. Part of the MacPorts install adds the dir for the MacPorts apps to the PATH:
    # Setting the path for MacPorts.
    export PATH=/opt/local/bin:/opt/local/sbin:$PATH
  22. However, when calling python from the command line, you will still get the Tiger default Python 2.3 because the MacPorts Python executable in /opt/local/bin is named python2.5, so make a symbolic link so that a call to 'python' will give you 'python2.5':
    sudo ln -s /opt/local/bin/python2.5 /opt/local/bin/python
Django source files
  1. Now that Python 2.5 and Postgresql are set up, it is time to install the Django source files. First, use the shell to find the site-packages dir for Python:
    python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
  2. Assuming you set the PATH correctly, the default MacPorts Python 2.5 install should give you:
    /opt/local/lib/python2.5/site-packages
  3. You can install the django source right there in site-packages, or you can install them in a separate directory and make a link. For my purposes, I want a dir for web dev, and inside it a dir for django, and inside that I want to install the django source code, so let's create that nested dir:
    mkdir -p ~/Webdev/django/src
  4. Next, move to the source dir and use svn to check out the dev trunk of django in this dir. This command will create a dir containing the dev version. This is the core code of django, and it will be kept separate from the projects that will be created with django:
    cd ~/Webdev/django/src
    svn co http://code.djangoproject.com/svn/django/trunk/ django-trunk
  5. Create a symbolic link to the django source in the site-packages dir:
    sudo ln -s ~/Webdev/django/src/django-trunk /opt/local/lib/python2.5/site-packages
  6. Create a symlink to make sure that the Python interpreter can load the django code:
    ln -s /opt/local/lib/python2.5/site-packages/django-trunk/django /opt/local/lib/python2.5/site-packages/django
  7. On Unix-like systems, first check your $PATH and then create a symbolic link to django-admin.py in a directory on your system path so that you don't have to type the full path when invoking it, so if `echo $PATH` shows that /usr/bin is in your path, you can make a link:
    ln -s /opt/local/lib/python2.5/site-packages/django-trunk/django/bin/django-admin.py /usr/bin
  8. See if `ls -l /usr/bin/django-admin.py` gives you something like:
    lrwxr-xr-x 1 root wheel 78 Dec 29 12:39 /usr/bin/django-admin.py -> /opt/local/lib/python2.5/site-packages/django-trunk/django/bin/django-admin.py
  9. The sites you make in Django are stored separate from the Django code, and all of this is outside of your public_html or /var/www directories. I choose to keep my projects in the django webdev dir:
    mkdir ~/Webdev/django/sites/
First project according to Django Tutorial
  1. Move to the sites dir and create a new project:
    cd ~/Webdev/django/sites/
    django-admin.py startproject mysite
  2. If postgresql is not running, turn it on and then login to psql:
    pgstatus
    pgstart
    psql template1
  3. In psql, create postgresql role django to use for django and then create the unicode database mysite with django as owner:
    create role django with superuser createdb login password 'agoodpassword';
    create database mysite encoding='UTF8' owner=django;
  4. Edit djangotests/mysite/settings.py, specifying:
    DATABASE_ENGINE = 'postgresql_psycopg2'
    DATABASE_NAME = 'mysite'
    DATABASE_USER = 'django'
    DATABASE_PASSWORD = 'agoodpassword'
    TIME_ZONE = 'Asia/Tokyo'
  5. Make sure you are in the project dir and then start the dev server included with python:
    cd ~/Webdev/django/sites/mysite
    python manage.py runserver
  6. Check the following link to make sure the django dev server is running on localhost:
    http://127.0.0.1:8000/
  7. Run the script to create tables for installed apps listed in settings.py:
    python manage.py syncdb
  8. This creates the tables needed for your test project. Use psql to take a look. Earlier, you created a superuser with the same name as the MacOSX login you are using, and you created the django user and the mysite database with django as the owner, so you should be able to access and examine the mysite database:
    psql mysite
  9. Use /dt in psql to describe tables (see all the tables in the database you are using), and use /d tablename to examine individual tables.
  10. From there, just follow the tutorial.