Monday, March 22, 2010

Half-Milestones

So one of the goals for my thesis is to get a working prototype of the Kukui Cup system ready in time for June. In order to do this, it was suggested that I switch to milestones every two weeks instead of every month (4 weeks). So, this week would mark a "half-milestone", which is fine except for that it's spring break! Fortunately, as a grad student, I don't really have much of a life anyway. Which means that milestone 2.5 is ready and up on GitHub.

Extending Models and Django

The specification I've been following recommends that there be two types of activities that users can commit to: events and regular activities. Events are basically activities with an additional "event date" field, which is required and indicates the date and time the event occurs. So, my initial idea was to have a base Activity model and another Event model that extends Activity and adds the additional required field.


class Activity(CommonActivity):
  CONFIRM_CHOICES = (
    ('text', 'Text'),
    ('image', 'Image Upload'),
  )
  
  confirm_code = models.CharField(blank=True, max_length=20)
  pub_date = models.DateField(default=datetime.date.today())
  expire_date = models.DateField()
  users = models.ManyToManyField(User, through="ActivityMember")
  confirm_type = models.CharField(max_length=20, choices=CONFIRM_CHOICES)

class Event(Activity):
  event_date = models.DateTimeField(null=True, blank=True)
However, adding this to the admin interface is a little tricky. Ideally, there would be one form to create activities or events by providing a drop-down with the options. Which is possible in the admin interface, but would require a little extra work to hack (especially if I want some fancy Javascript to hide/unhide the event_date field). Which is fine, cause I'm up for a little admin template hacking and I'll probably need to do it eventually. The other issue is that, in Django 1.0.4, events will show up in activities (which we want), but the template doesn't know if an activity is an event or not.

The simple solution then was to just create one activity with a boolean field "is_event" and the "event_date" field. Then, I created a custom admin form validator that checks if "is_event" is true. If it is true, then check if the "event_date" field is filled in. If it isn't, throw an error.

class ActivityAdminForm(ModelForm):
  class Meta:
    model = Activity
    
  def clean(self):
    """Checks that an event has an event date."""
    cleaned_data = self.cleaned_data
    is_event = cleaned_data.get("is_event")
    event_date = cleaned_data.get("event_date")
    has_date = cleaned_data.has_key("event_date") #Check if this is in the data dict.
    
    if is_event and has_date and not event_date:
      self._errors["event_date"] = ErrorList([u"Events require an event date."])
      del cleaned_data["is_event"]
      del cleaned_data["event_date"]
      
    return cleaned_data
And the template code is easy. We just check if the activity has the "is_event" field set and then print out the event date. The small catch is that regular activities can now set an event date, which isn't important to fix right now. Eventually, I'd like to do some admin hacking so that non-events have the "event_date" field hidden.

I'd also like to add that I found this awesome syntax highlighter at easy syntax highlighting for blogger.

No comments:

Post a Comment