I has a fevr… Django update
Been feeling terrible these last few days, down with the sickness of a fevr (Web 2.0 way of spelling it).
Django has become to me like a beautiful girl who is also a hacker. One in 6.2 billion. Today, I was working on making the database for ClassOwl a lot cleaner and more efficient (for scaling, of course) and I knew I had to use two columns in the database -- one to state the name of the model, and the other for the row ID in that model (table) where I would be pulling the data from. This makes it so I can have one master table that stores all the data, and allows me to create new types of things to be put in people's planners extremely easily.
For example, the three I am using right now are 1) homework 2) tests 3) events. But maybe some day after reader thousands of emails from users we would like to add something like class work as part of it. This would be simple, all I would have to do is create a new model (ClassWork) with all of the fields that are unique to a ClassWork object (time handed out, time due, maybe a discussion board). Doing it the way I have things set up right now, I would have to create a new model called ClassWork which has a lot of duplicate columns that homework/tests/events have, and then I would have to go in and add a bunch of code to my views to make it work. A big pain in the arse :).
Django makes this even simpler with it's Generic Relations. You specify the two columns (they give you a helper called ContentType which is amazing) and then add another line:
content_object = generic.GenericForeignKey()
And vualah! Now you can create a foreign key to any model you want, specify the primary key, and then access it with item.content_object when getting the data out of that row you are fetching. Man it seems like the only way they could make it better is if they started adding tons of "magic" features like they have in Rails... Actually, scratch that, I'm more of a control freak with my code, Django is perfect the way it is.
I LOVE YOU DJANGO.
Wow, I finally learned recursion.
One of the things that bothers me the most about programming is all the terms that everyone throws around. Sometimes I hear terms that I have no idea what they mean, and they sound really complicated, but in reality they are just big words and could be implemented by a 3 year old. So tonight I had to write this stupidly easy script.
It was like this: create a random 10 character string, and if that string exists in the database, create another random one until you have a unique string. So I wrote a function that was very practical; it did the job and made sense. I asked a question in the Django IRC to see if what I was doing was 1) right and 2) efficient, and somehow someone started talking about a recursive function. WTF is recursion? I hear this word all the time, I thought, but I never know what people are talking about. So I did what everyone with an IQ greater than 40 would do -- I Googled it. Turns out I've been writing recursive functions since I was 12.
Just because you know all the terms doesn't mean you're a great hacker. This post goes out to all you CS majors that know all the theory but can't code for sh......
Django and S3 – integrating
This was so much easier than I had anticipated. There are three things you need to do to get S3 up and running.
#1) Sign up on Amazon S3 to get the secret keys that you need (there are two of them). Don't want to spend time talking about this because it's a Google search away.
#2) Download the S3 library that Amazon gives out. Beautiful code in there.
#3) Set up your models so that you can store keys in them. I store some extra data just to make retrieval faster, content-type and name (original filename) because I plan on making it look like they are downloading it from my site in the future. Here is my exact code that took me about an hour to come up with (super super bare right now, will be writing more later on tonight/in the coming days)
site_s3.py:
import S3
import time
import sys
from django.conf import settings
AWS_ACCESS_KEY_ID = 'YOUR-KEY-HERE'
AWS_SECRET_ACCESS_KEY = 'YOUR-KEY-HERE'
# I declare this in my settings file so I can have a local bucket for testing and one for the server
BUCKET_NAME = settings.BUCKET_NAME
conn = S3.AWSAuthConnection(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
generator = S3.QueryStringAuthGenerator(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
def save_s3_data(key, data, content_type):
conn.put(
BUCKET_NAME,
key,
S3.S3Object(data),
{ 'x-amz-acl': 'public-read' , 'Content-Type': content_type }
)
return key
def delete_s3_data(key):
return conn.delete(BUCKET_NAME, key)
def get_s3_url(key):
return generator.make_bare_url(BUCKET_NAME, key)
MODEL:
from mysite.amazon import site_s3
class MediaFile(models.Model):
name = models.CharField(maxlength=200, blank=False)
key = models.CharField(maxlength=100, blank=False)
content_type = models.CharField(maxlength=100, blank=False)
upload_date = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=True)
def _get_file_url(self):
return site_s3.get_s3_url(self.key)
url = property(_get_file_url)
VIEW:
# this is extremely simple for example, I've cut out all validation (I do it in my view, too much for this post though)
copied_data = request.POST.copy()
if 'upload' in request.FILES:
copied_data.update(request.FILES)
if 'upload' in copied_data:
content_type = copied_data['upload'].get('content-type')
file = copied_data['upload']['content']
key = '%s-%s' % (request.user.id, ''.join(copied_data['upload']['filename'].split(' ')))
copied_data['key'] = key
# save it to S3
site_s3.save_s3_data(key, file, content_type)
if data['key']:
d = MediaFile()
d.name = data['upload']['filename']
d.content_type = data['upload'].get('content-type')
d.key = data['key']
d.save()
and finally...
TEMPLATE:
{% if assignment.attachment %} <a href="{{ assignment.attachment.url }}">Grab It</a> {% endif %}
Whew! So let's review that third step real quick.
In the file site_s3.py, I defined three methods. The first one saves the data to the S3 servers, and I invoke it in my view when uploading a document and makes it publicly viewable. The second one deletes an object if you tell it the key. I haven't used this yet, don't know why I included it haha, but it works. The third one retrieves a bare URL so that users can easily download the file.
In my model, I define a class MediaFile, so I can use a ForeignKey from any other model to this one so it can just store and retrieve all the URLs that I could ever want.
In my view, basically what I do is check if I have the file named 'upload' in the request, and if it exists, copy it into the request.POST data, which is copied_data. I also put the key in copied_data so I can retrieve it anywhere using copied_data['key']. This is probably stupid, but whatever, I'm just getting this going right now. I then save all the data to the database and right there is where I'd link 'm' to some other model as a ForeignKey. In this instance, I saved it to the FK of the model Assignment.
In my template, I just did a quick check to see if the attachment (MediaFile FK) existed, and if it did, render a link for someone to download the file. The variable {{ assignment.attachment.url }} gets the URL because url is a property in the MediaFile model.
And it all works PERFECTLY.
Thank God for Amazon. I love you guys ;).
Django – Find list of emails from a comma separated string
I need to start posting more code. Here's something I just did real quick.
from django.utils.html import simple_email_re
if request.POST['invite_list']:
post_list = request.POST['invite_list']
email_list = post_list.split(',')
list = []
for e in email_list:
email = e.strip()
if simple_email_re.match(email):
list.append(simple_email_re.match(email).group(0))
return list
Where post_list is something like "foo@foobar.com, somebody@whatever.com, jimmy@django.com" etc.
This will clean out that list just in case your user put in bad emails.
Okthanksbye
I will never have a “job”
I love writing code too much. I really don't think I will ever consider it a real "job" beause it is so much fun to me. Well, only when I'm working on projects that are cool.
I'm reading Founders At Work right now, by Jessica Livingston from YCombinator, and one of the thing the book stresses is the importance of just working on cool things. Who cares if you fail, you get 10x the experience that you would at a job where a boss tells you what to do, how to do it, and all that other crap.
Anyways. It's 4:15 and I'm sort of tired. Sorry for not blogging much anymore, I've been working my really hard on ClassOwl. Go there and add your email so you can be there when we go Live!
Nearness
ClassOwl is my first real company... The other ones I have loved, but I can see myself working on this project for the next few years. It's been over a year since I had the idea, and I believe in what I am doing 20x as much as I did when I first thought of it. This is my life right now:
Wake up in the mornings after having nice dreams, usually around 9 or 10pm. I get out of bed thinking about ClassOwl, because that is what my dreams have been about. Take a long shower, the whole time thinking about ClassOwl. Code for 2-3 hours then grab some lunch at Vazquez Deli in Downtown Vacaville. Thinking about ClassOwl the entire time. Go back, and code for 10-14 hours straight, usually falling asleep on my laptop.
Life has been like this starting 3 weeks ago from today. The question that I have constantly running through my head while I think of ClassOwl:
What can I do to increase the free flow of information?
No word on launch date, only a select few will get that information.
DRY: My New Favorite Acronym
One of the core principles of Django is DRY. DRY stands for Don't Repeat Yourself.
I have written hundreds of lines of code on the current Client Management System I am building for one of Okapi's clients, and I keep finding ways to not repeat myself in Python. Every time I state a static variable twice, I realize, that's repeating myself. It's time to write a function to return this variable!
I'm: Tired. Working hard. A mess.