Adding a field to the profile

From OpenHatch wiki
Revision as of 16:43, 5 July 2011 by imported>Mark

This is a page about improving or modifying OpenHatch.

We call that "Hacking OpenHatch," and there is a whole category of pages about that.


The set-up


Today, on July 4, 2011, my OpenHatch profile doesn't have a special field for my birthday. When I go to edit my profile, there's no place to put it in!

This tutorial walks you through adding that feature to the July 4, 2011 version of the OpenHatch code.

Together, we will change the OpenHatch source code, which builds on top of Django and Python. You'll see how to go all the way from a new feature idea to making and testing the change. On the way, you'll see how to search, study, and test your code.

The goal of this exercise is to show you the thought process we use when changing the website, give you confidence to try similar things on your own, and expose you to some helpful techniques that you might not know about.

Skills you need

In order to do this tutorial, you need to be willing to use a terminal and willing to learn some programming. The instructions are written for GNU/Linux systems, but Mac OS users will probably find the instructions work okay. (Windows users, I'm not sure.)

Getting help

If you try this and you get stuck, come come chat with us on IRC. Explain what you're doing, and what's not working, and we'll try to get you un-stuck. The same goes for if you can do the exercises but don't understand what they mean.


Getting the source

All the sample code in this walkthrough refers to version d56a354 of the OpenHatch source. To make sure the code is in line with what you expect, follow the instructions on the getting started with the OpenHatch code page. But right after you do the "git clone", do these commands:

$ git checkout d56a354 # Switch to that revision
$ git branch tutorial # Create a branch called tutorial that points at that revision
$ git checkout tutorial # Switch into that branch.

Here's how you can check that it worked. Run these commands in your new oh-mainline directory, and check that they have the same output as I've recorded:

$ git log -1 # look at the most recent commit on the current branch
  commit d56a354403026a1c3ecd634f2731e7d98a9513ff
  Author: Asheesh Laroia <asheesh@asheesh.org>
  Date:   Wed Jun 29 11:38:31 2011 -0400
   Add a config option that enables cookie sharing for Vanilla ProxyRequest-bas
$ git branch # see what the current branch is named.
  master
* tutorial


So far, so good? Let's dive in. (If not, chat with us on IRC!)

So that you and I see the same things, modify my actual profile! Import a data snapshot from July 4, 2011 (or the most recent one before this date)!

The 'What': What are we doing, again?

On your own development instance, open up Mark's OpenHatch profile in a browser tab. Inside the "Info" box, there are sections like my "bio" and "web site". It should look like the screenshot at the top of this page.

Let's add a new one, "birthday".

The 'Where': finding the right spot to make changes

Now we know what we want to see changed, but we still have to figure out what files to modify.

One way to find that out is to be methodical: we can open the urls.py file in a text editor. Since it maps web URLs into Python code that gets run, it is the starting point of how requests get dispatched in the OpenHatch source. Then you open up the appropriate view, find the template file it loads, and then you'll know what to edit.

Honestly, that sounds like a lot of work. I usually just search instead.

I'll warn you, though, that OpenHatch code can seem to be a sprawling mess. We'll use the "git grep" command to search it.

First, a word about git

Before you start using it, tell it who you are. When you do a commit, git will store this information in the repository.

 $ git config --global user.name "Your name"
 $ git config --global user.email "your.email.address@example.com"

Some tips on "git grep" before we begin:

  • It's like grep but accelerates the search by using the git repository you download.
  • It can color the matches.
  • To learn more, type "git grep --help" into your terminal. It will probably open a full-screen window; you can move up and down with the arrow keys. Quit by typing q.

Search 1: Find the template file that generates the info box

Let's search the code on your computer for the string 'web site'.

 $ git grep --color 'web site'
 mysite/expect-deploy:status "\r\n*** Reloading the web site... ***\r\n"
 mysite/profile/templates/profile/base_profile.html:        <h4>web site</h4>
 mysite/static/sample-data/open-opensolaris-bug.html: <a href="http://hub.opensolaris.org/bin/view/Main/help">Hel

These all start with mysite. That's where the OpenHatch code all lives.

One of these looks like a template file: base_profile.html. Open it up in a text editor, and you'll see this snippet:

        {% if person.homepage_url %}
        <h4>web site</h4>
        <p>
            <a rel="me" href="{{ person.homepage_url|prepend_http_if_necessary }}">{{ person.homepage_url|break$
        </p>
        {% endif %}

That seems to be what generates the person homepage link. It's in the context of a

<div id='info' class='module'>

Edit 1: Let's give everyone the same birthday

Okay, so let's edit the template so that every profile page says their birthday is January 1, 1980.

Just jam this right below the homepage section:

        <h4>birthday</h4>
        <p>January 1, 1980</p>

You'll get a box that looks like the picture. Note the birthday now shows in the profile block!

(You can read more about Django templates in the online Django book.)

Commit 1: Save our work

You have made some changes! Let's ask git to show them to us:

 $ git diff --color
  diff --git a/mysite/profile/templates/profile/base_profile.html b/mysite/profile/templates/
  index 1503658..864b3a7 100644
  --- a/mysite/profile/templates/profile/base_profile.html
  +++ b/mysite/profile/templates/profile/base_profile.html
  @@ -176,6 +176,9 @@
           </p>
           {% endif %}
   
  +        <h4>birthday</h4>
  +        <p>January 1, 1980</p>
  +
           {% if person.irc_nick %}
           <h4>irc nick</h4>
           <p id="ircnick" style='clear: both;'>

Let's save that change, and give it a name:

 $ git commit -a -m "base_profile.html: Now everyone's profile says they were born on January 1, 1980.

Edit 2: Adding a field to the Person model

If you take a look at template you just edited, you will notice that the person's website was referred to as "person.homepage_url". Since you also know that the code we want to edit is most likely in the "profile" module, you should start by looking in models.py, located in the "mysite/profile/" folder.

Open models.py and search for "homepage_url". The results of this search should leave you just inside of the Person class. If you look at the surrounding code, you should also notice other familiar fields (take a look back at the template changes you just made), such as irc_nick. Now you should feel confident that this is exactly where you need to add a new field for birthday.

At the end of the field definitions, just following the line that adds irc_nick, add a new field for birthday. According to the Django documentation, you want to use a DateField for storing dates. You will also want to tell the model that it is OK for someone to leave the field blank. You can do that by appending (blank=True) onto the new field.

  birthday = models.DateField(blank=True)


Edit 3: Adding the new field to the view

Adding a field to the model will ensure that we have a place to store the new field. You now need a way to access and update the data in this field. In Django, this is the responsibility of the view.

Find the view.py file located in the "mysite/profile" folder. Since you know that another field, 'irc_nick' is handled the same way as you want the new birthday field handled, you can easily find the right places to make changes to the code by searching for 'irc_nick'. Do that now and you will find the field added in the following functions.

In the edit_person_info_do(request) function, you will find the following line:

 # grab the irc nick
 person.irc_nick = edit_info_form['irc_nick'].data

Now edit that to add in a similar line for our new birthday field. Note: We will soon add the new field to the form.

 # grab the irc nick
 person.irc_nick = edit_info_form['irc_nick'].data

 # grab the birthday
 person.birthday = edit_info_form['birthday'].data

Continuing your search, you will notice that the 'irc_nick' field also appears in the edit_info function. Continue to make a change so that our birthday field appears there as well. Note: Don't forget the comma at the end of the line!

 'homepage_url': person.homepage_url,
 'irc_nick': person.irc_nick,
 'birthday': person.birthday,
 'understands': data['tags_flat'].get('understands', ''),

Inflection point

The next things to do are:

  • Create a form to capture the new field
  • Make the template changes so the new field appears in the profile block.
  • Write a migration file to add that column to our database.
  • Write a test.
  • Submit a patch.

Testing

Through all this, we've just been hacking and slashing until things work the way we want. But the OpenHatch code has all these automated tests, and we won't deploy new code that doesn't have automated tests written for it.