Bill, the cheese guy.

William Hyde

He was one of the nicest people I’ve ever met in my life, let alone on St. Thomas. His cool demeanor, his patience with everyone and his ability to bring a smile or introduce wonder into people’s lives was unrivaled around our little island. There are few people I’ve met who could successfully stump everyone with knowledge about a particular subject. People extremely familiar with his passion could still find something to learn; a moment to listen to Bill.

I spent many hours discussing the subtle differences between two parmesan cheeses with him. The dryness of one was due to one factor. The flavor of this due to another factor. What did the cows, sheep, or goats eat? What was the temperature like? Was there a cold snap somewhere in some weird place in the world that caused this certain coloration? Bill was sure to know.

He was never without a story about visiting the farms in far off towns in far off countries to see where certain cheeses were made. They were all captivating and wonderful. These were personal stories about him and his life. They were stories about where he had been and what he had done. He would leave out the parts about how much it must have meant to visit a small cave, where cheese was aged, on a farm in some remote area of the world. While exceptional, he wasn’t telling stories to talk about himself, he was telling stories to talk about his passion.

“To have lived a life like that and only deliver the information important to the subject at hand is an unselfish and exceptional trait in someone who is truly passionate about what they do.”

I met Bill through a friend and visited with him a few times a month to just talk about cheese and food. We’d talk about life sometimes, but we would eventually be drawn towards some new Morbier or a new Buffalo cheese that I should try. I couldn’t walk into Gourmet Gallery without visiting the cheese counter to see if he was there.

Peering across the store towards the back, you could see him moving deftly behind the counter, placing a particular cheese here, another there. Directing his employees, trying to get them to also be passionate about what they were doing. He would catch your gaze and a small smile would cross his face. The smile would turn to a grin as he would motion for you to come closer to the counter. As you start walking, you can see him slowly take off his gloves and walk to the back counter. There, he would move a few things out of the way and grab a couple of large boxes; their weight unclear in his confident stride.

The boxes would be plopped down and before opening them, Bill would greet you with a smile and ask how everything was going. While you responded, he would already be putting on his gloves and you could see the twinkle in his eye as he decided upon the perfect slice of cheese for you to taste. Without knowing it, you are suddenly tasting exactly the type of cheese you hoped you’d get by walking up to the counter. As you savor the experience of the incredible food he has just provided you with, he begins to open the boxes. Some new cheeses that had just arrived and he couldn’t wait to share them.

His face would light up as he would open the box.

“Oh! This is great. This is the truffled goat cheese that I was waiting for.”

“What does it taste like?” would be the question sure to be asked.

“I don’t know, let’s find out!”

As Bill would unwrap the cheese the story about the farm would begin to unfold. What the animals ate, where the farm was, what he had to go through to get this cheese to this remote island. A slice for him and a slice for you. The way he could describe cheese and food was great. He didn’t need to use a massive vocabulary of some pretentious sommelier. He knew what the flavors were, knew how to pick them out, knew what they were from, and he was correct.

I brought many friends to Gourmet Gallery, to the cheese counter to have an opportunity to meet Bill. It’s not very often that we get to meet people in life that are so incredibly passionate about what they do. People who have personal and wonderful stories about what they work with. People who aren’t afraid to share or teach. People who want to share something about the world with someone else because they love it so much.

That was Bill.

Bill was murdered, in part due to his kindness. He was abducted and beaten to death after trying to give a ride to one of his attackers. A minor, a teenager and someone he knew.

I write this in the hopes that more people can know what was senselessly taken from us. A kind, incredible and interesting individual at the age of 65, the day after Thanksgiving, just short of two months after finally hanging up his cheese gloves and taking a break for himself.

He addressed his friends one more time in his weekly emails regarding his free wine and cheese tastings:

Dear Friends,

Well, some good news and some sad news....

First the good news! This Thursday the 2nd Pre-order of French...and possibly in Gorgonzola Dolce, cheese will be touching down in St Thomas...
in perfect time for Friday's Wine and Cheese Tasting!

I haven't caught up with Phillip to see what wines will be offered so can be 
of no help there!

Now the sad news! I've resigned my position at Gourmet Gallery...sadly, as 
I said. I've been working 7 days and 5 nights for the past 2 1/2 years and I'm 
really, really tired. That being said, as complex as the new, expanded deli has really requires someone working many more hours than there are left
in my days and evenings!

I have enjoyed a great time getting to know you, our customers and sharing OUR 
enjoyment in good food, good wine...and most importantly, good company. I will 
miss you all!

Enjoy the Cheeses and Wines this coming Friday!


I will always enjoy cheese and wine a little more thanks to you, Bill. I hope to carry a fraction of your passion later in life, that I may share a love with the world as you shared with me.

Rest in peace.


There are a few different options that are often mentioned regarding Django and eCommerce services. I could have rolled my own but I’m trying to get better about giving previously built and tested libraries more of a chance before doing so.

After some research, I decided to give Satchmo a try for a shopping cart front. While I did come across some newer projects like Satchless, I wanted to see what the most popular one was up to. Satchmo was the most talked about and came up the most in conversations so I decided to dive in. The Quick Start guide got me most of the way there but I did hit a couple of hiccups that I thought I’d share with everyone.

First off, make sure you run everything in sudo.

My first step I didn’t read that Mercurial had to be installed. So if you miss that and get something like:

randomdrake:~$ sudo pip install -e hg+
Obtaining satchmo from hg+
  Cloning hg to ./src/satchmo
Cannot find command 'hg'
Storing complete log in /home/randomdrake/.pip/pip.log

Just run:

sudo apt-get install mercurial

Once I got things installed, I wanted to dive right in and start configuring things. With the project cloned, I fired up the server with a python runserver and hopped over to I was a bit disappointed to see that the text input box doesn’t properly fit on the default index page. Maybe that should be fixed somewhere?

But, no matter. I wasn’t after the design, I wanted the structure to build on top of. After clicking around for a bit, I thought it would be easy to find the template files and start to understand how the default page is done. Turns out I was a bit wrong. I started to browse through the source that gets installed by default for you. You can find it here:


After digging around for a little while and doing some finds, I decided to ask the Googles and see what I could come up with. Fortunately I found a little note in the Wiki that explained where I could start looking with a bit more clarity. So, to get rolling I hopped in the base.html file that is located here:


I simply copied this file into my local application’s /store/templates/shop/ directory and I was able to start hacking around on the layout.

Now that I had direct access to modifying the default template, I wanted to get it running in PostgreSQL. We can see, by default, it is setup to run in a SQLite database by looking in our /project/store/ file:

    'default': {
        # The last part of ENGINE is 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'ado_mssql'.
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(DIRNAME, 'simple.db'),  # Or path to database file if using sqlite3
        #'USER': '',             # Not used with sqlite3.
        #'PASSWORD': '',         # Not used with sqlite3.
        'HOST': '',             # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',             # Set to empty string for default. Not used with sqlite3.

After creating a new database and database user on my local machine, I simply filled the the values and ran the following:

python syncdb

A quick visit to my local host and I could see everything was working splendidly. I didn’t have any of the sample data to get in the way and I could simply start going through and creating my site completely from scratch. Just what I was looking for.

Hopefully you found this guide helpful to getting you up and running with Satchmo. If you liked this post, please follow me @randomdrake or consider following my feed.


The documentation from Heroku on how to start and deploy a Django application is quite excellent. Unfortunately, there’s not a lot of information out there on how to deploy something you’ve already written. In addition, the guide assumes you already have a decent amount of knowledge surrounding things like virtualenv. Because of this, I thought I’d go ahead and document the process this time instead of just angrily Tweeting about the problems and misunderstandings. Please feel free to comment any additional problems, or nuances you run into regarding doing this on Ubuntu.

First thing’s first, installing the Heroku toolbelt. While the simple command they give you seems pretty straightforward, there’s a small problem. They mention the following:

“The heroku command line client will be installed into /usr/local/heroku and /usr/local/heroku/bin will be added to your PATH.”

That’s all good except they don’t actually add it your $PATH for you. They add it to your ~/.bashrc file:

### Added by the Heroku Toolbelt
export PATH="/usr/local/heroku/bin:$PATH"

Because of this, you’ll need to restart your terminal or add it manually before you can easily complete the Heroku login instructions.

Alright, let’s go ahead and get logged in:

randomdrake:~$ heroku login
Enter your Heroku credentials.
Password (typing will be hidden): 
Authentication successful.

Excellent, we’re logged in. Now it’s time to let Heroku know what we need installed to run our app. The first thing that the Heroku guide instructs you through is creating your necessary requirements.txt file. One can do this by running the following command:

randomdrake:~$ pip freeze > requirements.txt

Unfortunately, just performing this outright in your Ubuntu environment produces an unnecessarily large requirements.txt

randomdrake:~$ cat requirements.txt

Because of this, we need to create a virtualenv to nail down our requirements. If you don’t have virtualenv, yet. You can get it get it through either of the following commands:

randomdrake:~$ sudo apt-get install python-virtualenv 


randomdrake:~$ sudo pip install virtualenv

Now that we have virutalenv installed, we can go about starting it up, installing our requirements, and getting an accurate requirements.txt. When I’m doing this step, I like to go to my file in my app to look and see what’s installed under INSTALLED_APPS. It will probably look something like this:

    # Uncomment the next line to enable the admin:
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',

This gives us an idea of what we’re going to need to install in our virtual environment. Let’s get started creating our virutal environment and installing those requirements. Go ahead and cd into the root of the directory where your app lives. From there, we want to follow the Heroku documentation:

randomdrake:~/myapp$ virtualenv venv --distribute
New python executable in venv/bin/python
Installing distribute.............................................................................................................................................................................................done.
Installing pip...............done.
randomdrake:~/myapp$ source venv/bin/activate
(venv)randomdrake:~/myapp$ pip install Django psycopg2 dj-database-url
Downloading/unpacking Django
  Downloading Django-1.4.1.tar.gz (7.7Mb): 7.7Mb downloaded
  Running egg_info for package Django
Downloading/unpacking psycopg2
  Downloading psycopg2-2.4.5.tar.gz (719Kb): 719Kb downloaded
  Running egg_info for package psycopg2
    no previously-included directories found matching 'doc/src/_build'
Downloading/unpacking dj-database-url
  Downloading dj-database-url-0.2.1.tar.gz
  Running egg_info for package dj-database-url
Installing collected packages: Django, psycopg2, dj-database-url
  Running install for Django
    changing mode of build/scripts-2.7/ from 664 to 775
    changing mode of /home/randomdrake/myapp/venv/bin/ to 775
  Running install for psycopg2
    building 'psycopg2._psycopg' extension
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -DPSYCOPG_DEFAULT_PYDATETIME=1 -DPSYCOPG_VERSION="2.4.5 (dt dec pq3 ext)" -DPG_VERSION_HEX=0x090106 -DPSYCOPG_EXTENSIONS=1 -DPSYCOPG_NEW_BOOLEAN=1 -DHAVE_PQFREEMEM=1 -I/usr/include/python2.7 -I. -I/usr/include/postgresql -I/usr/include/postgresql/9.1/server -c psycopg/psycopgmodule.c -o build/temp.linux-x86_64-2.7/psycopg/psycopgmodule.o -Wdeclaration-after-statement
    no previously-included directories found matching 'doc/src/_build'
  Running install for dj-database-url
Successfully installed Django psycopg2 dj-database-url
Cleaning up...

If you are familiar with the additional packages you need to install from your INSTALLED_APPS listing, go ahead and install them now. To see if you have successfully installed everything, try to run your server:

(venv)randomdrake:~/myapp$ python runserver
Error: No module named taggit

We can see that we are missing the taggit module. So we’ll go ahead and install that too.

(venv)randomdrake:~/myapp$ pip install django-taggit
Downloading/unpacking django-taggit
  Downloading django-taggit-0.9.3.tar.gz
  Running egg_info for package django-taggit
Installing collected packages: django-taggit
  Running install for django-taggit
Successfully installed django-taggit
Cleaning up...

Keep on doing this until you can successfully run your server:

(venv)randomdrake:~/myapp$ python runserver
Validating models...

0 errors found
Django version 1.4.1, using settings 'myapp.settings'
Development server is running at
Quit the server with CONTROL-C.

Now that we know we can run our server, we can freeze our requirements:

(venv)randomdrake:~/myapp$ pip freeze > requirements.txt

Take a look and see that we now have a nice, succinct list of requirements that we need for our particular app:

(venv)randomdrake:~/myapp$ cat requirements.txt 

You can feel free to leave your virtual environment now by issuing the deactivate command. You can also go ahead and remove the ./venv directory that was created with a little rm -rf venv action.

Before we go ahead and create our Heroku app, let’s let it know we want to use a different WSGI than the default. For some reason, they don’t document the process until after you’ve gotten your app up and running which, is a bit odd, considering it’s widely suggested to use an alternate. Follow the directions in the guide regarding “Using a Different WSGI Server” to setup gunicorn.

I personally like to setup a few gunicorn workers. So, I add a Procfile in the application root with the following:

web: gunicorn exampleapp.wsgi -b$PORT -w 10

This will ensure your Heroku installation has a few workers available to accept requests. Now we can go ahead and create our Heroku app! Hopefully you’ve already got your source code in a github repo. If not, get your own repo setup with your code first as you won’t be able to access your code as it’s committed to the Heroku repo. Now let’s follow the directions from the Heroku guide:

randomdrake:~/myapp$ heroku create
Creating tranquil-tundra-8486... done, stack is cedar |
randomdrake:~/myapp$ git push heroku master
fatal: 'heroku' does not appear to be a git repository
fatal: The remote end hung up unexpectedly

Well crap, that didn’t work quite as smoothly as expected. This is because Heroku isn’t recognized as a remote repository. You can see the remote repositories you have setup already:

randomdrake:~/myapp$ git remote -v
origin (fetch)
origin (push)

As one can plainly see, Heroku is not one of the ones listed there. No worries, we can add it as a remote option. When we did the heroku create command we were assigned a random app name. In our example: neat-narfy-4242. We can use this to add our correct remote heroku host:

randomdrake:~/myapp$ git remote add heroku

Now we can try our push again:

randomdrake:~/myapp$ git push heroku master
The authenticity of host ' (' can't be established.
RSA key fingerprint is 8b:48:5e:67:0e:c9:16:47:32:f2:87:0c:1f:c8:60:ad.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ',' (RSA) to the list of known hosts.

At this point, you may get an error like:

Permission denied (publickey).
fatal: The remote end hung up unexpectedly

If this is the case, it means you haven’t added your public key to Heroku, yet. Assuming you have already generated your keys for your system in your home directory, you can add your key with a simple command:

randomdrake:~/myapp$ heroku keys:add ~/.ssh/

Now you should be able to succcessfully deploy your app following the remaining instructions in the guide.

I hope that helped out. If you have additional issues doing this in Ubuntu 12.04, or just want to leave a message, feel free to comment below.

If you liked this post, consider subscribing to my feed or following me on Twitter at @randomdrake.