Exporting and Converting iPhone (iOS 9) Wallpaper Files

I found myself needing to export and convert iPhone (iOS 9) wallpaper files from an old iPhone, and the source photos for these files no longer exist. As with most things Apple this turned out to be a horrendous pain but I was determined not to let Apple win. To paraphrase Ferris Bueller, “If I’m gonna get busted,  it is not gonna be by a company like that.”

Although getting here was pretty time-consuming, the end result is simple. I did this on Windows but it should work on a Mac as well, provided you can install Pillow and run some Python.

  1. Connect the iPhone to your computer
  2. Backup the iPhone using iTunes
  3. Grab iExplorer and run it, allowing it to connect to the iPhone
  4. In the Backup Explorer, navigate to HomeDomain -> Library -> Springboard
  5. In that directory you’ll see HomeBackground.cpbitmap and LockBackground.cpbitmap files, along with .jpg thumbnails of the files. Export these files from iExplorer to your computer.
  6. The .cpbitmap files are worthless (except to the iPhone) on their own, so finally you need to run a Python script to convert the .cpbitmap files to a usable image file.

I had to mess with some of the various Python scripts I found online to get it working properly (this one came closest), so if you’re reading this at a future date or using a different version of iOS, I won’t be surprised if it needs further tweaking.

Hope that helps others retrieve their wallpaper files!

Installing Python 3 and Django on Dreamhost

I’m working on a side project for a friend that has zero budget and since I’m already paying for Dreamhost (my favorite and only choice for shared hosting) and totally underusing it, I figured I’d use this project as my opportunity to figure out how to install Python 3 and Django since A) Dreamhost lets you do install things even on their shared platform (one of the reasons I love them!), and B) the default Python on Dreamhost is Python 2.7.3.

1. Install Python 3.5.1

This part’s really simple and Dreamhost even documents it nicely on their knowledge base, but for the sake of one-stop shopping I’ll include the steps I performed here. Note that I’m leaving the default Python 2.7.3 in place since I’m not sure what havoc it would wreak to blow it away, so Python 3.5.1 will be installed in such a way that it’ll be run as python3. (For the curious, you can also read more about Python at Dreamhost in general.)

Before going any further, if you haven’t enabled SSH access for your Dreamhost user you need to do that first since if you can’t log in you can’t install anything.

  1. Log into the Dreamhost web panel
  2. Click on “Users” and then “Manage Users”
  3. Find the relevant user and click the edit button
  4. Under “User Type” choose “Shell user,” and I’d recommend also choosing /bin/bash as the shell type
  5. Scroll to the bottom of the page and click “Save Changes”

Next, we’ll install Python 3.5.1.

  1. Go to https://www.python.org/downloads/release/python-351/ and get the URL for the gzipped source tarball.
  2. SSH into your Dreamhost server
  3. In your user’s home directory, wget the tgz file using the URL you grabbed in step 1:
    wget https://www.python.org/ftp/python/3.5.1/Python-3.5.1.tgz
  4. Extract the Python source:
    tar xvf Python-3.5.1.tgz
  5. cd into the extracted source directory:
    cd Python-3.5.1
  6. Configure Python 3.5.1 with a prefix flag so as not to stomp on anything that’s already installed:
    ./configure –prefix=$HOME/opt/python-3.5.1
  7. Run make and make install:
    make && make install
  8. Add the new Python installation to your path:
    export PATH=$HOME/opt/python-3.5.1/bin:$PATH
  9. Update your bash profile:
    . ~/.bash_profile
  10. Verify that everything’s working (this should output Python 3.5.1):
    python3 -V
If that all looks good at this point, we’re ready to proceed and create a virtualenv in which we’ll install Django.

2. Create a virtualenv

Python 3 ships with pyvenv, but since it works a bit differently than virtualenv which is what I’m used to using, I decided to install virtualenv and use that. Feel free to use pyenv here if that floats your boat.
  1. Use pip3 to install virtualenv:
    pip3 install virtualenv
  2. Create and/or cd into the directory in which you want to put your virtualenv. I tend to put mine in ~/.virtualenvs, so I did this:
    mkdir ~/.virtualenvs
    cd ~/.virtualenvs
  3. Create a virtualenv to use for our Django project (since we installed virtualenv with pip3 the default Python environment will be Python 3.5.1):
    virtualenv my_django_project
  4. Activate your virtualenv:
    source my_django_project/bin/activate
  5. Confirm everything looks correct at this point (this should output /path/to/virtualenv/bin/python3):
    which python3
If we’re still on track we can proceed to install Django.

3. Install Django (and your other requirements)

At this point since we have Python 3.5.1 installed and have successfully created a virtualenv, we can do the usual installation of requirements using pip3, which typically will come from a requirements.txt file. For the sake of illustration we’ll go through installing Django into our virtualenv and making sure it works, but pip3 install -r requirements.txt will be the more typical way of installing all the packages you need.
  1. With your virtualenv activated, install Django:
    pip3 install django
  2. Verify everything is working by starting a Python interpreter:
    python3
  3. Import Django to make sure it’s in your virtualenv (this shouldn’t throw any errors):
    >>> import django
Now that we have verified that our virtualenv is working and sane, we can proceed to the rest of the configuration to get a Django project running successfully in this environment on Dreamhost.

4. Enable Passenger on Your Web Site

Rather than the gunicorn or some of the other WSGI servers you may be familiar with, on Dreamhost you can use either Passenger or FastCGI as the application server for Django applications.

For this post I’ll be using Passenger, a tool with which I was not familiar until I saw information about it on Dreamhost. Passenger is apparently more common in Ruby on Rails setups, but it serves the same purpose and falls in the same place in the stack as any of the other WSGI tools with which you may have experience. You can read more about Dreamhost’s use of Passenger here and here.

Some Notes About Passenger

Worthy to note about using Passenger on Dreamhost is that once Passenger is enabled, all requests that come into your domain will be handed off to Passenger by Apache. Passenger will first look see if there are any files matching the request in your domain’s /public directory (and note that the files must be in the /public directory or subdirectories under /public specifically), and if it can’t find an appropriate file, Passenger then tries to handle the request itself.

To provide a couple of concrete examples, let’s assume you have a file called hello.html in your domain’s /public directory, and a request comes in for http://yourdomain.com/hello.html. Here’s what happens next:

  1. Apache hands the request off to Passenger immediately. This is important to note since Apache is out of the picture entirely other than serving as a proxy to Passenger.
  2. Passenger looks for a file called hello.html in your domain’s /public directory. Since it finds one, it returns that page to the requester.
Now let’s assume a request comes in for http://yourdomain.com/some/django/url. Here’s what happens in that case:
  1. Apache hands the request off to Passenger.
  2. Passenger looks for an appropriate file in /public. This time it doesn’t find one.
  3. Passenger then attempts to handle the request itself, and since later we’ll be configuring Passenger to serve up our Django application using WSGI, at this point Django would be processing the request.

Enable Passenger

In order to run a Django application on Dreamhost we’ll need to enable Passenger on the domain on which we’re going to run our Django application.

  1. Log into the Dreamhost web panel
  2. Click “Domains” and then click “Manage Domains”
  3. Locate the domain on which you’ll be hosting your Django application and click “Edit”
  4. Scroll down and under “Web Options” you’ll see a checkbox labeled “Passenger (Ruby/NodeJS/Python apps only).” Check that box.
  5. Scroll to the bottom of the page and click “Change Settings.”
That’s it for enabling Passenger. Next we’ll throw our Django application at Dreamhost and see what sticks.

5. Create a Django App

For the purposes of this post we’ll be creating and configuring a Django application directly on the Dreamhost server. Obviously if you have an application that’s already written that you want to run on Dreamhost you’d be uploading your application’s files as opposed to doing things from scratch on the server, but this should illustrate some of the nuances of what you need to do with your own Django application to get it running on Dreamhost with Passenger.

  1. ssh into the Dreamhost server
  2. Activate the virtualenv you created above:
    source ~/.virtualenvs/my_django_project/bin/activate
  3. cd into the root directory of the web site on which you’ll be running your Django application. Note that this is not the aforementioned /public directory under your web site’s directory, but the root of the web site itself.
  4. Start a new Django project using django-admin.py:
    python3 django-admin.py startproject my_django_project
  5. Do a quick gut check by firing up the Django development server:
    cd my_django_project
    python3 manage.py runserver
At this point you should see the Django development server start up without any errors. We’re nearly there! The last step is to configure this newly created Django application to work with Passenger. But before we do that, a quick note about static files.

Serving Static Files and the Static Root Setting

It wouldn’t be Django if we didn’t have to stop and say a word about serving static files. Luckily this isn’t anything out of the ordinary, but given how Passenger works you do need to be aware of how to set your STATIC_ROOT to make sure everything comes together smoothly.

  1. Create a static directory under your domain’s public directory, i.e. you’ll wind up with ~/yourdomain.com/public/static
  2. Go into your Django project’s settings file and add a STATIC_ROOT setting:
    STATIC_ROOT = os.path.dirname(BASE_DIR) + ‘/public/static/’
With that you should be all set to run collectstatic and have everything work properly. Now let’s move on to configuring Passenger.

6. Configure Passenger

In order to have Passenger load up our Django application, we need to create a passenger_wsgi.py file in the root of our domain. As with all WSGI files this is what tells the application server, in this case Passenger, how to load up the application so it can handle requests.

In the root of your domain, create a passenger_wsgi.py file with the following contents:

With that file in place, you should be able to hit http://yourdomain.com and see the default “Congratulations” Django page. Congratulations indeed! You now have a Django application running on Python 3.5.1 on Dreamhost.

A common error you might run into is something like “no module named foo” or “no module named foo.settings.” If you get something along these lines it means your paths are incorrect, so make sure that your Django project is in a directory directly inside your domain’s root, not in the /public directory. If that isn’t the issue, double-check all the paths in the passenger_wsgi.py file.

Additional Passenger Considerations

It’s worth noting that if you change your passenger_wsgi.py file you need to run pkill python to reload the Django application since Passenger loads your application into memory (which is one of its advertised advantages since it makes things pretty zippy).

I also saw note of having to run touch tmp/restart.txt but in my experience I didn’t have to do that, so I’m not sure if that’s more of a Rails thing or if I simply didn’t yet run into situations in which that was necessary. I’m noting it here in the event pkill python doesn’t do the trick.

Final Notes

There you have it. You now have the latest Python and Django running on Dreamhost. At this point you can load your own Django project, set up a database (note that Dreamhost only supports MySQL, and even though I much prefer Postgres, MySQL works just fine), and do all the usual Django stuff.

Enjoy!

Installing PyGame with Python 3.5 on Windows 10

Quick installation notes for PyGame with Python 3.5 on Windows 10 since the available installers didn’t work for me, the symptom being the apparently highly frequent “pygame module has no attribute init” error when trying to call pygame.init() after importing pygame.

First if you’ve run any PyGame installers previously, make sure to clean up anything they installed. The easiest way to do this is to run the installer again and choose the uninstall option, but you may also want to check the Lib/site-packages directory under your Python installation to make sure there aren’t any remnants.

Next, go here and download the appropriate .whl file for your environment.

Next, open a command prompt and run:
pip install wheel

Finally, browse to the directory where your downloaded .whl file is located and run:
pip install pygame_file_name_here.whl

Restart your command prompt to be safe, and at that point you should be able to do this in a Python interpreter without getting errors:
import pygame
pygame.init()

Hope that saves someone else some head against desk time.

Python 2.7, Django, Apache, and Gunicorn on CentOS 6.5

I’m working on a little Django project for KPTZ Radio in Port Townsend and since this project has to talk to a serial relay board from a specific server that has other things running on it, I’ve been going through the process of installing Python 2.7 on CentOS 6.5, along with configuring Django, Apache, and Gunicorn.

Since I’m a lot more used to dealing with Nginx and Gunicorn on Ubuntu, getting this all up and running correctly took a lot more trial and error than I thought it would, but I finally got it figured out so figured I’d share since I found a lot of either incomplete or misleading information about this as I searched for solutions.

Installing Python 2.7

Your first question is probably why I’m not installing Python 3. In the case of this particular project, pyserial was not (when I first started the project) Python 3 compatible, so rather than fight that battle I decided to use Python 2.7.

The problem with Python 2.7 is on CentOS 6.5, Python 2.6.6 is the default, and since there’s other Python-related stuff running on the server already I didn’t want to run the risk of screwing anything else up, so I had to install Python 2.7 as an alternate Python installation. Luckily there were a couple of resources from people who had already been through this so it wasn’t an issue. Here’s the steps I took on a fresh CentOS 6.5 VM I was using to do some trial runs before doing everything on the production server (do all these as the root user).

  1. yum -y update
  2. yum -y groupinstall “development tools” –skip-broken
  3. yum -y install wget gcc gcc-c++ make httpd-devel git vim zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel
  4. wget https://www.python.org/ftp/python/2.7.10/Python-2.7.10.tgz
  5. tar xvf Python-2.7.10.tgz
  6. cd Python-2.7.10
  7. ./configure –prefix=/usr/local –enable-shared LDFLAGS=”-Wl,-rpath /usr/local/lib”
  8. make && make altinstall
  9. python2.7 -V (to confirm it’s working)
  10. cd ..
  11. wget –no-check-certificate https://pypi.python.org/packages/source/s/setuptools/setuptools-18.2.tar.gz
  12. tar xvf setuptools-18.2.tar.gz
  13. cd setuptools-18.2
  14. python2.7 setup.py install
  15. cd ..
  16. curl https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py | python2.7 –
  17. pip2.7 install virtualenv

Create a User to Own the Project

Depending on how you want to do things this could be considered optional, but I created a user to own the project files (again as root):
  1. useradd -m -s /bin/bash/someuser

Create a Python virtualenv and Install the Django Project

Next we’ll create a Python 2.7 virtualenv, grab the Django code, install the Django project’s requirements, and do a couple of other configuration things for the Django app.
  1. sudo su – someuser
  2. mkdir ~/.virtualenvs
  3. cd ~/.virtualenvs
  4. virtualenv foo –python=python2.7
  5. cd foo
  6. source bin/activate
  7. cd ~/
  8. git clone foo
  9. cd foo
  10. pip install -r requirements.txt
  11. python manage.py runserver (just to make sure things are working at this point)
  12. python manage.py collectstatic
  13. python manage.py migrate

Configure Upstart to Start the Gunicorn Process When the Server Boots

I suppose on the next version of CentOS this will be done with systemd but thankfully on CentOS 6.5 we can still use Upstart. Note that if you’re familiar with Upstart on Ubuntu the syntax is quite different on CentOS — thanks to my good friend and former coworker Brandon Culpepper for pointing that out before I lost my mind.
First, we’ll do a quick test to make sure everything’s working at this point:
  1. sudo su – 
  2. cd /home/someuser/foo
  3. /home/someuser/.virtualenvs/foo/bin/gunicorn –workers 4 –timeout 60 –bind 0.0.0.0:8000 foo.wsgi:application
  4. Hit Ctrl-C to kill the process if you don’t see any errors.
Next we’ll create the upstart file:
  1. vim /etc/init/foo.conf
  2. Put the following in the foo.conf file and save it:
    description “Gunicorn process for foo app”

    start on started sshd
    stop on shutdown

    script
      cd /home/someuser/foo
      /home/someuser/.virtualenvs/foo/bin/gunicorn –workers 4 –timeout 60 –log-level debug –bind 0.0.0.0:8000 foo.wsgi:application
    endscript

  3. start foo (to make sure the upstart process works)
  4. ps -wef | grep python (you should see some python processes running under your virtualenv)

Create Apache Virtual Host for the App

There’s a bunch of ways to set up Django apps with Apache. In my early days with Django I would have used mod_wsgi but since I’m way more used to Nginx and Gunicorn these days, I figured I’d set up Apache in similar fashion and have it proxy to Gunicorn.
  1. vim /etc/httpd/conf/httpd.conf
  2. Uncomment the NameVirtualHost *.80 line if it isn’t already uncommented
  3. Add a new VirtualHost section at the bottom of the Apache config file:
    <VirtualHost *:80>
      ServerName whatever
      DocumentRoot /home/someuser/foo

      # serve static files from Apache
      RewriteEngine on
      RewriteRule ^/static/.* – [L]

      # proxy everything else to the gunicorn process
      ProxyPreserveHost on

      RewriteRule ^(.*)$ http://127.0.0.1:8000$1 [P]
      ProxyPassReverse / http://127.0.0.1:8000/
    </VirtualHost>

  4. apachectl restart
At that point you should be all set! Hope that helps people who are in this same or a similar boat save some time.

Python 3 + Oracle on Ubuntu Server 14.04

I’ll invite my readers to check my previous post on this topic to get a sense of how I feel about Oracle.

Small updates it seems to get cx_Oracle working with Python 3 on Ubuntu 14.04. Assume sudo/root for all the following.

  1. Download the RPM versions of both the basic and SDK clients for 11.2.0.4 from http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html
    1. Note: If you’re not familiar with the idiotic hell that is Oracle downloads, you have to do this on a browser where you can click a radio button and THEN download, so wget from the server on wish you actually want to install this stuff is unfortunately a no go.
    2. The 12.x version of this stuff still doesn’t work with cx_Oracle. At least not for me.
  2. scp the rpm files to the target server
  3. ssh to the target server
  4. apt-get install libaio1 alien
  5. For both the RPMs:
    alien -d RPM_FILE_NAME
  6. For both the newly created Debian packages:
    dpkg -i DEBIAN_PACKAGE_NAME
  7. touch /etc/ld.so.conf.d/oracle.conf
  8. echo “/usr/lib/oracle/11.2/client64/lib” > /etc/ld.so.conf.d/oracle.conf
  9. echo “export ORACLE_HOME=/usr/lib/oracle/11.2/client64” >> /etc/environment
  10. echo “export LD_LIBRARY_PATH=$ORACLE_HOME/lib” >> /etc/environment
  11. source /etc/environment
  12. ldconfig
  13. pip3 install cx-oracle
  14. Put the relevant tnsnames.ora in $ORACLE_HOME/network/admin
Note that unlike my previous instructions you can install cx_Oracle using pip3 once you have everything in place. Maybe you could use pip before but I seemed to have better luck with the converted RPM, and at that point I was kind of tearing my hair out so I probably didn’t go back to take a run at it using pip once the Oracle bits were sorted.
The big change here is the necessity to install both the basic client and the SDK client packages for Oracle; it worked with Python 2.7 on Ubuntu 12.04 without the SDK package.

Dynamically Adding Forms To and Removing Forms From Django Formsets

For my latest big project I am running into numerous situations in which I need to dynamically add forms to and remove forms from Django formsets, which turned into an interesting and fun challenge, and led to a lot of learning about how Django formsets work along with some ancillary details (like the behavior of the jQuery UI datepicker when you manipulate the DOM) that I wasn’t necessarily expecting to encounter.

To set the stage for the discussion by way of a concrete example, one aspect of the application in question is the ability to request leave (e.g. vacation, sick leave, etc.), and as you might imagine on the leave request page you can add days to and remove days from your leave request.
In the first iteration of this feature (random aside: we do Kanban and try our darndest to focus on “good enough” features, particularly on early iterations, so that we can deliver the most usable functionality in the least amount of time, looping back around to make improvements as time permits), each form in the leave formset has the following fields:
  • date of leave
  • start time of leave
  • end time of leave
  • hours of leave
  • minutes of leave
Why does the user have to specify the number of hours and minutes they’re taking for their leave if they’re providing the start and end times, you might ask? Basically it boils down to people with access to the leave calendar wanting to know the specific times people are out, which may not always match up with the amount of leave they’re taking.
For example if you take a full day of leave, let’s say you’re out 8 am to 5 pm, but there’s a lunch hour in the mix, so the clock time you’re out is 9 hours, but the amount of leave you have to take for the full day is only 8 hours. And again, “good enough” is the focus on this first iteration. This basic functionality lets people request leave, and in future iterations, time permitting, we’ll make the system smarter and remove some of the burden off the user with things like calculating hours based on start/end times, taking into account weekends and holidays, letting people select date spans, and all sorts of other niceties that are in our backlog.
But back to the discussion at hand, namely how this all happens with Django formsets. Since the last thing I wanted to do was have the leave form code as a variable in a JavaScript function, I decided to go the route of grabbing a new instance of the form via Ajax when the user clicks the “Add Day” button. That way the leave form code lives in one place, in a normal Django template, and is therefore much more maintainable.
This immediately got interesting, however, given how Django formsets work. By default (i.e. if you aren’t using the prefix option in the formset constructor), forms in Django formsets will all have ids along the lines of id_form-0-field_name, and names along the lines of form-0-field_name, where 0 is the index corresponding to the form’s position in the overall formset. So if you have multiple forms the first form will have an index of 0, the second one will have an index of 1, etc.
Also in the mix is the Django formset’s management form, which contains the information necessary for Django to manage and process the formset, such as the total number of forms, the minimum and maximum number of forms allowed, and so on. The key point here is that if you’re going to be dynamically adding and removing forms, you also need to be updating the form-TOTAL_FORMS value in the management form in order for things to stay in sync.
As you might be guessing by now, the syntax of the form fields in a formset doesn’t quite mix with making an Ajax call out of the blue to an otherwise oblivious Django template to get a new form. Thankfully that was pretty easy to resolve by making sure to get the next form number and including that in the Ajax call:

And the form template (small snippet here) simply includes the form number in all the necessary places to make the form gibe with what the formset expects:

So when you get the form back from the Ajax call it has the correct number in all the fields, and all is right with the world.

Or so it would seem. [cue dramatic music]

At this point if all you ever want to do is ADD forms to a formset, this approach works perfectly. Where things get weird is when you start removing forms from your formset, since the aforementioned form indices get all kinds of screwed up (to use a technical term) if you don’t adjust them as you go.

When I first started adding the remove functionality I was optimistically thinking, “Oh Django probably doesn’t care about the form indices so much. I’m sure as long as the total number of forms it has in the management form matches the number of forms in the formset, it won’t care if the indices go 0, 1, 4, 7, or whatever.”

And that’s actually partially true. I’ve gone through so many iterations of everything prior to writing this blog post that you’ll have to forgive me for slightly fuzzy details here, but my recollection of the first incarnation of this feature is that yes, indeed, I could add and remove rows to my heart’s content, and as long as I was ensuring the next form number was incremented, and the total forms value in the management form was right, I could post the formset, validate the formset, route back with errors, and that all worked.

Where things proved interesting is when our QA folks took a crack at this, they (as QA folks tend to do) did something I hadn’t:

  1. Add a few rows to the form, and set the dates (N.B. we’re using jQuery UI’s datepicker for this; that fact becomes important in a moment)
  2. Add another new row and don’t set the date
  3. Delete one of the rows in the middle of the set of rows
  4. Set the date using the datepicker in the last row that was added
At that point what would happen is that the date selected in the final row would change the value of the date in one of the rows above it. Also if you submitted the form that way with errors, when it came back and rendered the populated forms, some of the forms were blank.
This turned out to be a great find that set me down the path of learning a whole lot of stuff I’m glad I learned now before it bit me later.
Attacking the two problems (1. Django forms don’t re-render correctly in an error state, and 2. datepicker changes the wrong date) in sequence, my first thought went back to the Django formset indices and my optimistic assumption that the indices didn’t matter as long as the number of forms in the formset matched the total forms value in the management form.
This, not surprisingly, turned out to not be the case. As I said earlier if you only add forms things are incremented nicely and nothing gets out of whack, but I was now finding that when a form was removed, what needed to happen is that all the existing form fields needed to be reindexed so they started with 0 and incremented sequentially. A bit of JavaScript handled that without too much trouble. (I’ll put the solution below since it involves problem #2 as well.)
Even after I got the form indices back into a sequential state as forms were removed, however, the datepicker was still behaving badly. I’d add and remove forms in random order and in some cases the datepicker would still change the wrong date field (in a predictable fashion with respect to the index), or throw an error that it couldn’t find the form field to which it was attached.
That latter error led me to the solution for this problem. The long and short of it is that when you remove something from the DOM that has a datepicker attached to it, you have to destroy and reattach all the datepicker elements because each datepicker retains a reference to the field to which it was originally attached.
To sum up what has to happen when a form is removed for everything to behave properly:
  1. Resequence all the form indices so they start at 0 and increment sequentially; and
  2. Destroy all remaining datepickers and recreate them
To keep things simple the remove link on each form looks like this:

That way I didn’t have to keep track of the index on the delete button too, I could simply reference its form container parent and go from there.

With that in place the delete row function wound up looking like this:

Main things of interest there are getting a handle on the delete link’s parent form via the form class, and lines 13-16 where the datepickers are destroyed and rebound so they get attached to the correct form field.

And of course the call to updateFormElementIndices(), the bit that resequences the form indices, which was inspired by various snippets and other solutions I found to address this issue and looks like this:

Pretty straight-forward, but to go over what’s happening there:

  1. Get a handle on all the forms of the class passed to the function and loop over them
  2. Get the current index number of the form being updated
  3. Update the form index to the loop increment (0-based, sequential)
  4. Get all the inputs with the class matching the form class passed in, plus ‘Input’ at the end
  5. Loop over the inputs, changing the IDs and names in similar fashion to how we updated the form ID
With all that in place Django was happy, the datepicker was happy, and (hopefully) our QA folks will be happy as well.
As I said this was a great find not only because I learned a ton slogging through this today, but also because this was the first incarnation of a pattern that will occur in numerous areas throughout this application (adding multiple phone numbers being the next example), so it was nice to catch this early and fix it in such a way that I can do it right on the future instances of similar functionality.
As far as the code goes, it works for the leave form I’ve been describing here, but I’m sure as I work on the future similar functionality I’ll find ways to make it more generic and flexible for more generalized use. The reliance on having to put related classes on the forms and inputs makes things handy for the JavaScript, but is an additional requirement as far as the development goes that may not ultimately be necessary.
But there you have it. It works, I learned a ton, and I share it here both so it might help someone else having to do this, and also so someone who knows more than I do can point out that I may be doing it in a more complicated way than necessary.

Python + Oracle on Ubuntu Server 12.04

Affectionately known among all non-masochists in the world of IT as The Seventh Circle of Hell (with real hell being preferable), working with Oracle is always a hair-tearing nightmarish fork-in-the-eye please-for-the-love-of-god-kill-me-now experience that none but those who look to Ted Bundy, Jeffrey Dahmer, and John Wayne Gacy for moral and spiritual guidance would wish upon even their most reviled enemies.

Yes, it’s that bad. And apparently nowhere is it worse than when one attempts to get Oracle working with Python on Ubuntu.

I’m not even talking about installing the Oracle database server itself here people, I’m just needing a Python application to talk to an existing Oracle database. One would think, as with every other database server on the planet (and yes, I’m including that other slice of hell SQL Server in that statement since it’s a damn sight simpler to get working — even on Linux — than Oracle), you’d simply apt-get and/or pip install a library or two and be done with it.

If you actually do think that, you’ve already forgotten that this is Oracle we’re talking about.

That said, one does what one has to do to keep the paychecks coming, so if you need to do this here’s the steps to make it all happen. (Note that on Step 1 I’m assuming you have already installed all the other Python packages you may need. I’m focusing on the stuff you may not have that you definitely need.)

  1. sudo apt-get install libaio1 alien
  2. Download the RPM of version 11.2.0.4.0 of the Oracle client from http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html (note that as of the date of this writing the 12.x version doesn’t work, or at least didn’t for me)
    1. You have to have an Oracle Web Account and use that to log in and download this, which makes using wget on the target server itself or automating the process for use with something like a Vagrant provisioning script rather problematic. Short version, you’ll have to download this locally and then scp it up to the target server. What I did is downloaded and converted this RPM as well as the other necessary RPM, converted them once, and put them in a git repo from which I can clone in my Vagrant provisioning script. Whether or not that adheres to the licensing agreement, I don’t know and I don’t care. If you’re paranoid, check with a lawyer before repeating my solution on this.
    2. If the version number differs slightly from what I have here, adjust later steps accordingly.
  3. Download the RPM of the Python 2.7/Oracle 11g version of the cx_Oracle Python libraries from http://cx-oracle.sourceforge.net/
  4. scp the RPMs up to the target server as needed.
  5. Convert the RPMs to Debian packages using alien:
    sudo alien -d FILENAME.rpm (where FILENAME is of course the name of each of the two RPM files)
  6. sudo dpkg -i oracle-installclient11.2-basic_11.2.0.4.0-2_amd64.deb
  7. sudo vim /etc/ld.so.conf.d/oracle.conf
    1. Note: this file won’t already exist, so you’ll be creating this as a new file in this step
  8. Enter the following in the newly created oracle.conf file and save it:
    /usr/lib/oracle/11.2/client64/lib
  9. export ORACLE_HOME=/usr/lib/oracle/11.2/client64
  10. export LD_LIBRARY_PATH=$ORACLE_HOME/lib
  11. sudo ldconfig
  12. sudo dpkg -i cx-oracle_5.1.2-2_amd64.deb
  13. cd /usr/lib/python2.7
  14. sudo mv site-packages/cx_Oracle* dist-packages
  15. sudo rmdir site-packages
  16. sudo ln -s dist-packages site-packages
  17. Verify installation by opening a Python interpreter and run the following:
    import cx_Oracle
    1. If you don’t get an import error, everything is working properly

As far as automating this for use with Vagrant,  in my provisioning script I simply echoed the export statements in the steps above into /etc/environment, did source /etc/environment and followed that with ldconfig. Other than that the steps in the bash script are pretty much what’s above, but if people are interested in seeing the script let me know and I can post it.

And there you have it. A lot of trial and error and head bashing went into that final solution, and since I kind of cobbled together the steps from various resources I’ll post those below in case you want to see some of the other solutions and source material.

Happy Oracleing. Or not.

References

  1. http://iambusychangingtheworld.blogspot.com/2013/06/python-oracle-sqlalchemy-on-ubuntu-1304.html 
  2. http://maxolasersquad.blogspot.com/2011/04/cxoracle-on-ubuntu-1104-natty.html 
  3. https://linuxindetails.wordpress.com/2009/12/26/installation-of-python-cx_oracle-module-for-debian-squeeze/
  4. http://stackoverflow.com/questions/12538238/python-module-cx-oracle-module-could-not-be-found

Generating CSV Files in Django

This is a very quick tip since it’s so simple but I did run into one little wrinkle with string encoding while doing this so I thought I’d share.

I had a request to generate a CSV of all the Old Dog Haven “Walk for Old Dogs” registrants so the fine folks managing the event can do email blasts, print registration sheets, and the like.

Since Python has CSV functionality as part of the standard library the generation of the CSV data was very easy, and since the Django HTTP Response object was quite wisely designed to behave as a file-like object, writing the CSV data to the HTTP response was dead simple as well.

The only thing I ran into while writing the data to the response object was there were some non-ASCII characters in the database which threw this error:
‘ascii’ codec can’t encode character u’xe9′ in position 4: ordinal not in range(128)
 
To get around this it was just a matter of tacking .encode(‘utf-8’) to the end of the string objects when writing out the CSV data.

Here’s the final result.

Custom Managers in Django

I had to add a bit of functionality to the Old Dog Haven “Walk For Old Dogs” registration and sponsorship site today (feel free to sponsor me!), specifically a way for the good folks running the event to see an aggregate total of the sponsorship dollars by registrant.

Here’s the Django models for Registrant and Sponsor:
Pretty straight-forward — main thing to notice is that Sponsor has a foreign key relationship with Registrant as opposed to the other way around. And yes, in its current incarnation sponsors can only sponsor one registrant; if they want to sponsor multiple registrants they simply create another sponsor record. (It’s agile baby — release early and often! Multiple sponsorships can happen next year!)

While calculating the total sponsorship dollars by each registrant could be handled via the Django ORM, I decided to use the opportunity to execute SQL directly in a function in a custom manager.

You can read more about custom managers in the Django docs, but the short version is that when you call something like Foo.objects.all() the objects bit refers to the model’s Manager class, and it has all sorts of default functionality built in allowing you to easily interact with your model.

Referring back to the Sponsor and Registrant model code above, notice that since we’re using a custom model manager, in the Sponsor model I added the line objects = SponsorManager() to override the default model manager with the custom one for which we’ll see the code below.

As with most things in Django, model managers are easily extended and overridden, and in this case I wanted to add a new function to the Sponsor manager to return a list of registrants with a sum of their sponsorship amounts. This was as simple as adding a SponsorManager model that extends model.Manager and adding a function called with_sponsorship_totals to return the information I need.
Again, pretty straight-forward. SponsorManager extends models.Manager, we add the code to run the SQL query we want to execute, loop over the results and add instances of the Registrant model to the results list, and return the results.

One of the other great things I should point out about Python is the ability to add fields to classes on the fly. The Registrant class doesn’t have a total_sponsorship_amount or team_name field defined, but I can add those as I loop over my results so they’re available in the list returned by the custom manager function.

Another approach to solving this problem might be to add a function to the Registrant model itself that would calculate the total sponsorship amount for each registrant, but I opted to create a custom manager in this case to experiment a little, and I also thought it taking this approach would be more efficient than calculating individually for each registrant.

As you can see from this basic example, creating a custom manager for your Django models is an extremely simple, powerful way to add functionality to your application and is nothing to shy away from. By creating fat models and extending model managers where needed you can keep the business logic where it belongs and avoid a lot of unnecessary complexity in views and other areas of your application.