Building Rallyhat: Importing Schedules

I continue to be impressed with Django as I build out Rallyhat. I have an extreme alpha version working on my laptop, minus the Yahoo! Maps stuff I've been playing around with. The biggest task was populating my database with the schedules for all the baseball teams. I thought I'd share what the import script looks like:

PYTHON:
  1. #!/usr/bin/env python
  2. from django.core.management import setup_environ
  3. import settings
  4. setup_environ(settings)
  5. from rallyhat.www.models import Team
  6. from rallyhat.www.models import Game
  7. from rallyhat.www.models import Location
  8. from rallyhat.www.models import Sport
  9.  
  10. from datetime import date
  11.  
  12. import csv, urllib, time
  13.  
  14. s = Sport.objects.get(name='Major League Baseball')
  15. teamSchedules = Team.objects.all()
  16.  
  17. for teamSchedule in teamSchedules:
  18.     scheduleFile = teamSchedule.schedule
  19.     print "Importing games for " + str(teamSchedule.name)
  20.  
  21.     if scheduleFile != "":
  22.         reader = csv.reader(urllib.urlopen(scheduleFile))
  23.  
  24.         for row in reader:
  25.             teams = row[3].split(' at ')
  26.  
  27.             if len(teams) == 2:
  28.                 if Team.objects.filter(name=teams[1]).count() == 0:
  29.                     print "Adding new team: " + teams[1]
  30.                     homeTeam = Team(name=teams[1], sport=s)
  31.                     homeTeam.save()
  32.                 else:
  33.                     homeTeam = Team.objects.get(name=teams[1])
  34.  
  35.                 if Team.objects.filter(name=teams[0]).count() == 0:
  36.                     print "Adding new team: " + teams[0]
  37.                     awayTeam = Team(name=teams[0], sport=s)
  38.                     awayTeam.save()
  39.                 else:
  40.                     awayTeam = Team.objects.get(name=teams[0])
  41.  
  42.                 gameDate = time.strftime("%Y-%m-%d", time.strptime(row[0], "%m/%d/%Y"))
  43.                 startTime = time.strftime("%H:%M", time.strptime(row[2], "%I:%M %p"))
  44.  
  45.                 # If this game doesn't exist, add it to the system
  46.                 if Game.objects.filter(home_team=homeTeam, away_team=awayTeam, game_date=gameDate, start_time=startTime).count() == 0:
  47.                     locationCheck = Location.objects.filter(name=row[4]).count()
  48.  
  49.                     if locationCheck == 0:
  50.                         print "Adding new location: " + row[4]
  51.                         l = Location(name=row[4])
  52.                         l.save()
  53.                     else:
  54.                         l = Location.objects.get(name=row[4])
  55.  
  56.                     locationId = l.id
  57.                     g = Game(home_team=homeTeam, away_team=awayTeam, location=l, game_date=gameDate, start_time=startTime)
  58.                     g.save()

It's interesting to treat everything as an object after so many years of being in the PHP world where you can mix and match depending on what's been going on in your application. I'm also amazed at how clear the code is. There is some non-intuitive stuff in there, especially when dealing with the saving of model records. It took me a while to figure out I could pass the object containing the model as a parameter when saving a record for a model that it is associated with.

Article Tags >> || ||

Union Of The Snake, Part 1

C'mon ,you know that Duran Duran kicks ass! I was trying to think of a catchy title for a series of posts as I wind my way through the building of my first Python app, using the Django framework. If you've used any other framework, you should be able to follow along with these posts as the concepts are all pretty much the same.

First off, I have great hopes that the current CakePHP 1.2 manual can morph into a resource as great as The Django Book, which looks to me to be the essential resource for anyone wishing to start off with Django. Everything I'm doing at this stage in the project builds on what I've covered so far.

Anyway, I've chose to build out Rallyhat, my sporting road planning site. Much like when I build a CakePHP app, I start out with the models. Django has a pretty good ORM component, as compared to the associated data mapping model that CakePHP uses. Now, to paraphrase from the Django book: "introspection is hard", so in order to give the Model ORM some help you define the fields you will be using in your models. Here are the definitions I'm using:

PYTHON:
  1. from django.db import models
  2.  
  3. class Sport(models.Model) :
  4.     name = models.CharField(max_length=30)
  5.        
  6.     def __str__(self):
  7.         return self.name
  8.  
  9.  
  10. class Team(models.Model):
  11.     name = models.CharField(max_length=30)
  12.     sport = models.ForeignKey(Sport)
  13.     city = models.CharField(max_length=30)
  14.     state_province = models.CharField(max_length=30)
  15.     country = models.CharField(max_length=30)
  16.  
  17.     def __str__(self):
  18.         return self.name
  19.                
  20.                
  21. class Game(models.Model):
  22.     home_team = models.ForeignKey(Team, related_name='home_team')
  23.     away_team = models.ForeignKey(Team, related_name='away_team')
  24.     start_date = models.DateTimeField()
  25.     sport = models.ForeignKey(Sport)
  26.    
  27.    
  28.     def __str__(self):
  29.         return '%s vs. $s' (self.away_team, self.home_team)

As you can see, I'm able to define all my fields I'm going to use with generic data types, and can even define the associations between the tables. So, why do we do all this? Well, Django comes with some great CLI tools for helping you build stuff. In fact, I dare say that you cannot build a Django application *without* using these tools. Once you've defined the models you want to use, you validate the models using 'python manage.py validate', and it reports any problems it found.

While I was building this out, it told me that it couldn't determine the foreign keys I wanted, so I quickly figured out I had to put Sport first in the definition list, then Team, so that Game would know what to reference for the foreign keys. It also told me that I had to set a 'related_name' attribute for my foreign keys in Game since I was reference the same model twice for a foreign key. Very similar to how you can alias an association in Cake.

Okay, once that's done I can then get it to generate the actual SQL needed to create those models using 'python manage.py sqlall rh' (with 'rh' being what I'm calling the application within Django). In this case I'm using a Postgres backend, so it generated SQL specifically for Postgres.

SQL:
  1. BEGIN;
  2. CREATE TABLE "rh_game" (
  3.     "id" serial NOT NULL PRIMARY KEY,
  4.     "home_team_id" integer NOT NULL,
  5.     "away_team_id" integer NOT NULL,
  6.     "start_date" timestamp WITH time zone NOT NULL,
  7.     "sport_id" integer NOT NULL
  8. )
  9. ;
  10. CREATE TABLE "rh_sport" (
  11.     "id" serial NOT NULL PRIMARY KEY,
  12.     "name" varchar(30) NOT NULL
  13. )
  14. ;
  15. ALTER TABLE "rh_game" ADD CONSTRAINT sport_id_refs_id_66e4cc9c FOREIGN KEY ("sport_id") REFERENCES "rh_sport" ("id") DEFERRABLE INITIALLY DEFERRED;
  16. CREATE TABLE "rh_team" (
  17.     "id" serial NOT NULL PRIMARY KEY,
  18.     "name" varchar(30) NOT NULL,
  19.     "sport_id" integer NOT NULL REFERENCES "rh_sport" ("id") DEFERRABLE INITIALLY DEFERRED,
  20.     "city" varchar(30) NOT NULL,
  21.     "state_province" varchar(30) NOT NULL,
  22.     "country" varchar(30) NOT NULL
  23. )
  24. ;
  25. ALTER TABLE "rh_game" ADD CONSTRAINT home_team_id_refs_id_20e54e34 FOREIGN KEY ("home_team_id") REFERENCES "rh_team" ("id") DEFERRABLE INITIALLY DEFERRED;
  26. ALTER TABLE "rh_game" ADD CONSTRAINT away_team_id_refs_id_20e54e34 FOREIGN KEY ("away_team_id") REFERENCES "rh_team" ("id") DEFERRABLE INITIALLY DEFERRED;
  27. CREATE INDEX "rh_game_home_team_id" ON "rh_game" ("home_team_id");
  28. CREATE INDEX "rh_game_away_team_id" ON "rh_game" ("away_team_id");
  29. CREATE INDEX "rh_game_sport_id" ON "rh_game" ("sport_id");
  30. CREATE INDEX "rh_team_sport_id" ON "rh_team" ("sport_id");
  31. COMMIT;

Man, it creates the indexes too! Okay, now that I'm happy with that all I have to is 'python manage.py syncdb' and it goes and actually creates the tables (and indexes) for me. I took a look at the 'schema' task that exists for the Cake console (try 'cake schema' if you have already configured the console for use and poke around) and it will do similar things for you. Nicely done, gwoo!

(chartjes@jackjack ~/Sites/rallyhat)
>python manage.py syncdb
Creating table rh_game
Creating table rh_sport
Creating table rh_team
Installing index for rh.Game model
Installing index for rh.Team model
(chartjes@jackjack ~/Sites/rallyhat)
>

Bingo, presto! We have our tables created for us!

I hope you've enjoyed this little glimpse into Django (and how it relates to CakePHP, in an obtuse way I guess). Next time we invoke the spirit of Duran Duran, I'll be showing how I built a search form to find all games for a particular team, showing how Django's MTV (Model-Template-View) system works.

Article Tags >> || ||

Moving From Herding Elephants To Handling Snakes

Since the summer, something had been bothering me about PHP. I couldn't put my finger on it but over the holidays I finally figured out what was wrong. After ten years of working with PHP, I'm bored with it. Every professional programming job I've ever had has involved PHP as the main language, with a smattering of things like SQL, Perl, Ruby and Javascript. But it's always PHP at the core.

So what is there left for me to do with PHP? I'm not about to write my own PHP framework as I have one I already like, one that I use for my simulation baseball league's web site. I'm not a C programmer, so diving into the internals of PHP to contribute that way is a no go. No, it's time to put PHP aside (so to speak) and pour my energies into something else.

A while back I tried the Rails thing. I liked it...because it was so different from PHP. Ruby has such elegant syntax, reading like English in many ways. I even got asked to create a training course for Ruby on Rails, but never got far with it (sorry Marco). Once I started poking around more about Rails, I started to see things that made me uneasy about it: issues about performance in high-traffic environments, the attitude of some of the more senior "core" guys in Rails, and the zealotry displayed by users of it.

Slam PHP all you want for it's syntax ($object->chaining->looks->weird()), it's inconsistency in function parameter order, the still-ongoing debate about how to implement namespaces, and the combo of powerful functionality combined with a low barrier of entry (thereby infuriating programming snobs). But it gets shit done, plain and simple. That's how Rasmus Lerdorf started off using PHP, that's how it will always be. Elegance in code and proper programming techniques are the domain of the developer, not the language in my not-so-humble opinion.

Sure, Ruby is nice and Rails has all those cool magic functions but some stuff I read by Zed Shaw (the creator of Mongrel put into words a lot of what I had felt about Rails: just not for me, I guess.

So what's left? Not gonna go the Java route: too much pain and suffering lies down that path. So, I'm left looking at a language that is rock solid, has a great object model, has a good web application framework to help me get up to speed and lots and lots and LOTS of great documentation and tutorials: Python.

I won't be giving up getting PAID to do PHP code any time soon because I have a great job with a great bunch of guys, and I get to work from home. But I just feel it's time to focus my energies on something else. Python is very similar to Ruby, and let's be honest here: I've got enough programming experience that there shouldn't be much of a learning curve for me to figure out Python. Python code just looks nice and clean, less writing to get more done. That's what I'm really looking for these days.

The simball web site continues to grow and get new features, so I will be leveraging CakePHP to the hilt in that respect. It's an exciting time for CakePHP as they are heading towards 1.2 and preparing for 2.0. But I am not sure what my contribution to the project will be any more, which hasn't been much lately but I am interested in helping push the CLI tools forward as not only can they help me, they can help other developers as well. But it is time for a change. Maybe one of these days I find a job programming in Python, or even manage to push Python in through the back door where I currently work. But the time is absolutely right for me to start learning Python and make it a tool I want to use on a regular basis instead of it continually being on my list of "things to do when I feel up to it".

I've got my copy of "Dive Into Python" in PDF, been going through the Python tutorials (wow, the interactive interpreter is great) and getting ready to bust out a Django install. But make no mistake: PHP pays the bills, but it's time to start using other people's tools to get the job done. Time to quit fooling myself that I'm going to make some sort of earth-shattering contribution to PHP, and save my brainpower for learning Python the way I've learned PHP.

Wish me luck!

Article Tags >> ||

Opinionated Software, The Podcast

A while back I was contacted by Cal Evans over at the Zend Developer Zone to contribute to a new podcast he was starting up called PHP Abstract. Very cool idea, a small 5 to 7 minute podcast by PHP developers where they talk about a topic of interest to them (and hoepfully to you). Well, being one to never miss out on an oppurtinity to promote myself I agreed to contribute what I could. I settled on a brief talk about opinionated software. Also known as "convention over configuration" by the Ruby on Rails crowd.

Go over and have a listen and don't be shy in sharing your feedback via the comments there or here. Opionated software / convention over configuration / tools with rules is a powerful yet misunderstood programming practice.

Glue vs. Full Stack

[Note: looks like the move to the new server will take some time as I configure things *just so* so blogging can continue]

So I'm sitting around thinking about how I'm going to build out the new rallyhat.com, turning it into a "plan a baseball road trip site" and figuring out what tech to use. To be honest, I've gotten kind of bored with Ruby on Rails for a few reasons. One is that I understand the tech behind Rails, and don't agree with a lot of the magic methods that Ruby seems to be encouraging. I like to sort of understand what's going on rather than being told "just do it this way". I don't understand Ruby enough to wade into the source for Rails and figure things out. Secondly is that I haven't touched any Rails code in months, so any momentum I had has leached out.

So, I like to learn new languages because, well, it makes me a better programmer. I've spent my time this year learning my way around Javascript so I can get a firm grip on just how all this Ajax stuff is supposed to work. Now I'm glancing over at Python and trying to decide if I want to invest in learning Python so I can try out Django, a web application framework that gets lots of nice things said about it. Not as flavour-of-web-pi that Rails has become, but a solid, well-documented web application framework.

So naturally I do some research and found an interesting post about Python web development frameworks that talks about Django vs. Pylons vs. Turbogears. Very interesting reading and it convinced me that Django is the way I should go if I'm going to become a snake handler on this project. But I followed some other links and got to a page (can't find it now of course but I remember it) where there was a discussion of glue vs. full stack frameworks.

A glue framework provides you with a bunch of components that you can use together, but don't necessarily have to. Zend Framework is a PHP glue framework, as it comes with all these cool components that you can pick and choose depending on what you need done. You're not forced to use them, and this appeals to certain programmers who have fallen in love with their own quirky set of libraries and methodologies. This used to be me. To shift this over to Python, since I know no Python at this point i would be pointless to go with a glue framework.

A full stack framework gives you everything you need to create your web app, and pretty much forces you to use it. CakePHP is a full-stack framework. It has a bunch of conventions, and you must follow them or die. Okay, maybe you won't die but your application will never work properly if you don't understand the conventions. Django is a full-stack framework. So, given my knowledge level of Python I think that would be my safe choice.

However, I have the Imp of the Perverse mumbling into my ear that I should just build the damn site, screw Python because we're tying to get something done here. So I'm thinking that I need to put my money where my mouth is, and build in CakePHP. After all, I have that cool interactive console to test stuff with.

So, give me some feedback: which do you prefer when building an application? Full stack or glue?

Want to advertise on this blog? Send email to chartjes@littlehart.net
GTcars Canadian Car Audio TurboDodge Car For Sale Sign
Audi Forum Mustang Forum Dodge Intrepid Miata Turbo
GTscene Pontiac Bonneville