iA


Step Four: Writing your Django models

by Andy Boyle.

Now that you can FTP into your server and have a database set up, it’s time for the fun to begin: Building your first project!

As I mentioned in Step Two, we’re building FireTracker, your fancy Tracker Of Fires app. And with that, you need to know how Django works in order to build the damn thing.

Django builds what are known as models-view-controller, or MVC, applications. They’re all the rage, and allow people to work on different parts at the same time for more efficiency. Ruby on Rails is another MVC that people use. I know Django better, and that’s why we’re building this app in Django.

Your models.py file is where you set up your data architecture, or in simpler terms, it’s sort of where you set up spreadsheets with field names and what type of data will go in it (numbers, words, etc.).

Your views.py is where you tell it “hey, look at the models so we can tell the template how to spit stuff out.” And then the template is where your HTML and design lives, and it talks to the view and spits stuff out.

So let’s talk about what we want this app to do.

WHAT WILL THIS DAMN THING DO

You want to track fires that occur in your coverage area, right? Well, as Adrian Holovaty once talked about:

For example, say a newspaper has written a story about a local fire. Being able to read that story on a cell phone is fine and dandy. Hooray, technology! But what I really want to be able to do is explore the raw facts of that story, one by one, with layers of attribution, and an infrastructure for comparing the details of the fire — date, time, place, victims, fire station number, distance from fire department, names and years experience of firemen on the scene, time it took for firemen to arrive — with the details of previous fires. And subsequent fires, whenever they happen.

So think of it this way. You get a report of a fire from the scanner. You run out to cover it. This fire incident has data, including the date/time, the address, the city, the state, the people involved (which includes homeowners, victims and fire department/police), injuries (which will relate to the people involved), and the monetary damage done to the place set on fire. You gather these facts and normally write a story.

And the data, which can be structured into something more useful, just dies in a story. That’s it. Well, this app will change that. It’ll catalog the data mentioned in the previous graph. It may not be the most scientific thing, but these are the types of projects that every news organization that covers a city could build. And thus you shall build it, o wonderful hacker-journo pioneer.

WELL HOW DO I DO THAT

First we need to set up the models.py file. That’s where your data architecture lives. If you’ve done any work with SQL, some of this may seem familiar. Let’s begin.

First, download some sort of text editor. Here’s a link to a few good free ones. I prefer Coda, of course, but to each their own. What you code in doesn’t really matter, although we pretend like it is. After you’ve downloaded it, start a new file and name it models.py. Open it up. This is where we will type our code.

Now, with Django, you have something called a class. In real simple terms, think of each class as an individual spreadsheet page. It has fields, rows and connections to other spreadsheets (classes). So first we need to build the location portion. A location has a street address, a city and a zip code. A city has a state. So we need to build an individual class for state, zip code, city and then location. It looks like this:

from django.db import models

class State(models.Model):
    name = models.CharField(max_length=50)
    name_slug = models.SlugField()
    short_name = models.CharField(max_length=8)
    def __unicode__(self):
        return self.name

class City(models.Model):
    name = models.CharField(max_length=150)
    name_slug = models.SlugField()
    state = models.ForeignKey(State)
    def __unicode__(self):
        return self.name

Now let me explain to you how this works. Each of these are classes, which are tables within the big FireTracker database. A state has a field name, a field name_slug, and a short name. A city has a name, its name_slug and a state. Because the city NEEDS a state, you need to make that class first. If the City needed a color field, for some instance, you would have also made that class BEFORE the City class.

The name_slug is used for urls, and the def __unicode__ business is so you can spit out the name in the admin and other spots quicker. Trust me, it’ll all make sense later.

Well, what other classes do we need? Well, we need fire departments, people, the location of the fire, an all-encompassing fire class, and others. Here’s the entire thing, and if it doesn’t make sense right now, that’s okay, just take a gander at what a functional app’s models.py file looks like:

from django.db import models

class State(models.Model):
    name = models.CharField(max_length=50)
    name_slug = models.SlugField()
    short_name = models.CharField(max_length=8)
    def __unicode__(self):
        return self.name

class City(models.Model):
    name = models.CharField(max_length=150)
    name_slug = models.SlugField()
    state = models.ForeignKey(State)
    def __unicode__(self):
        return self.name

class Department(models.Model):
    name = models.CharField(max_length=150)
    name_slug = models.SlugField()
    short_name = models.CharField(max_length=15)
    def __unicode__(self):
        return self.name

class Title(models.Model):
    title = models.CharField(max_length=50)
    title_short = models.CharField(max_length=10, blank=True, null=True)
    title_slug = models.SlugField()
    employer = models.ForeignKey(Department, blank=True, null=True)
    def __unicode__(self):
        return self.title

class Person(models.Model):
    first_name = models.CharField(max_length=150)
    last_name = models.CharField(max_length=150)
    name_slug = models.SlugField()
    dob = models.DateField(blank=True, null=True)
    title = models.ForeignKey(Title, blank=True, null=True)
    experience = models.IntegerField(blank=True, null=True)
    def __unicode__(self):
        return "%s %s" % (self.first_name, self.last_name)
    def get_absolute_url(self):
        return "/firetracker/person/%s/%s" % (self.id, self.name_slug)

class Address(models.Model):
    street = models.CharField(max_length=150)
    street_slug = models.SlugField()
    city = models.ForeignKey(City)
    property_value = models.IntegerField(max_length=12, blank=True, null=True)
    owner = models.ManyToManyField(Person, blank=True, null=True)
    def __unicode__(self):
        return self.street

class Station(models.Model):
    name = models.CharField(max_length=150)
    name_slug = models.SlugField()
    department = models.ForeignKey(Department)
    address = models.ForeignKey(Address)
    def __unicode__(self):
        return self.name

class StoryLink(models.Model):
    link = models.CharField(max_length=250)
    headline = models.CharField(max_length=250, null=True, blank=True)
    date = models.DateField(null=True, blank=True)
    def __unicode__(self):
        return self.headline

class Injury(models.Model):
    injury = models.CharField(max_length=150)
    injury_slug = models.SlugField()
    def __unicode__(self):
        return self.injury

class Victim(models.Model):
    person = models.ForeignKey(Person)
    injury = models.ForeignKey(Injury)
    def __unicode__(self):
        return "%s %s" % (self.person.last_name, self.injury.injury)

class Source(models.Model):
    source = models.ForeignKey(Person)
    def __unicode__(self):
        return self.source.name_slug

class Cause(models.Model):
    type = models.CharField(max_length=150)
    type_slug = models.SlugField()
    def __unicode__(self):
        return self.type

class Fire(models.Model):
    location = models.ForeignKey(Address)
    cause = models.ForeignKey(Cause, blank=True, null=True)
    date = models.DateTimeField(blank=True, null=True)
    monetary_damage = models.IntegerField(blank=True, null=True)
    respondings = models.ManyToManyField(Station, blank=True, null=True)
    response_time = models.DateTimeField(blank=True, null=True)
    extinguish_time = models.DateTimeField(blank=True, null=True)
    story_links = models.ManyToManyField(StoryLink, blank=True, null=True)
    victims = models.ManyToManyField(Victim, blank=True, null=True)
    source = models.ForeignKey(Person, blank=True, null=True)
    def __unicode__(self):
        return "%s on %s" % (self.location, self.date)
    def time_took(self):
        return self.response_time - self.date
    def extinguish_time_took(self):
        return self.extinguish_time - self.response_time
    def get_absolute_url(self):
        return "/firetracker/fire/%s/%s" % (self.id, self.location.street_slug)

Kind of complicated, isn’t it? Well, that’s the point. Each class contains a field that will eventually be called later from our database and spit out onto a page. Or it will be used to help make a url. The last three parts — def time_took and whatnot — are defining variables that we will use later. Maybe if you look at the words and the math you’ll figure out what we’re calculating here.

Now, using your text editor, you will copy and paste this code into a file you will name models.py. You will then upload it to your /opt/django-projects/firetracker/ directory.

So boom. Your models are done. Next we will create a database and sync the models to it. And then we will create an admin so you can look at what you’ve made and enter data in the backend. So move on to Step Five.

No comments on ‘Step Four: Writing your Django models’

Leave a Reply