SnakesAndRubiesTranscript Transcript of the video of the Django Presentation by Adrian Holovaty Slides available from: http://www.snakesandrubies.com/presentations/adrian/ ---- ==== Introduction ==== Hey guys, thanks for coming out, I'm Adrian, one of the developers of Django, which is a Python web framework. Nice to see that a lot of you guys were Python developers. First I'm going to show you a little bit about the background of Django - where it came from. it was derived out of a real world application, so, in order to understand django, it's kind of important to understand the culture it kind of came out of. I know that sounds really exciting, but... Basically, I'm Adrian, I live here in chicago, grew up in the suburbs, I work for washingtonpost.com as editor of editorial innovations, which is a fancy title for basically Mad Scientist - I get to do cool stuff with the website, like basically build database driven applications on a deadline. I've only been doing that for three months. Before that I was actually living in Kansas - which is not quite as bad as you might think (slide: Kansas board of education) (Laughter) It's actually a lot better than that because I lived in a town called Lawrence, Kansas, really cool college town - got a great music scene, there's a lot of cool bars and restaurants and stuff - very very cool place. But that's not the reason I moved there. I moved there because the newspaper is really really good. I've got a news background - my background is between programming and journalism. I develop news web applications. This web operation in Lawrence, Kansas is really really cool, really really cutting edge and they do a lot of really really cool stuff, so I went to work there. ==== Adrian's background with lawrence.com ==== I'll give you an example of one of the cool things that we did. I told you about the music scene in Lawrence; uh, we said ok, wouldn't it be cool if there were a site you could go to that represented Lawrence, all the music scene had, all the stuff, all the events happening, all the bars and restaurants, that stuff. So we made this: Lawrence.com Lawrence.com is easily the most in-depth local entertainment site in the world; this thing fricken kicks ass. Starting out with the basics, it has an events calendar, which is you know, every entertainment site has one, has the standard stuff, when and where it's happening, what the cost is, but when it gets really interesting is the bands database. I don't know if you know allmusic.com, but it's essentially allmusic.com at a local level, plus it ties into the events database, so that on this band's page it says that they have shows at the Granada on Friday, at the on Tuesday, and it pulls in all the genres, all the biographical information about the band, and everything's in a huge database, so that when you go to the page for this band, you can see oh - those are the musicians in the band, click on one of the musicians and you can see all the other bands he's in, you can see OK - this guy plays pedal steel, so you click on pedal steel, you see all the other people in town that play pedal steel. It's just kind of, this huge database of all local entertainment, and because it's very music oriented, every band has song clips, and we have entire MP3s, around a thousand MP3s of all local music, which is very very intense. The way this stuff integrates is very very cool; on the events page, if you're looking at a band in the band database, it'll pull in those links and say related band pages, it'll look at those bands and say ok, do any of these bands have songs in the songs database? Yes, in this case there were, so it says if you go to this event, you might hear these songs, blah blah blah blah blah. So we're doing some really cool things. Including a radio station that's this little flash-wizzy interface that automatically grabs all the songs for a particular band, there are genre stations, you can make your own stations - which are called playlists - it's very very interactive site, you can create your playlist, you can comment on other people's playlists, you can comment on essentially any object in the system. There's an album discography database; you can comment on any band, any event, any story in the blogs, there's an intense restaurant database with not only the basics like which cuisine it is, and which region, but also whether it's a homey's favourite (*laughs*) - the site authors refer to themselves as the homies - whether it's vegetarian friendly, and whether it accepts barter (*laughs*). No restaurant in Lawrence accepts barter, but we've been thinking of adding a little thing with adding that, where if you search for it, it says, like, "are you stupid?", or something. But, the point is, it does a lot of cool stuff. Because we have all the restaurant closing and opening times, we're able to say here are all the restaurants that are open right now, so at 4pm or whatever time it is now, it's not very impressive, but if you're drunk at 1am and you want to get some grub, you can go to this page and there's all the stuff that's still open. Speaking of being drunk, there's a drinks specials database, which is updated every day and has all the drinks specials for every bar in town every day. People actually print this thing out, and put it next to their beds - I'm not making this up - Simon's roommate used to do this. And you can export drink specials to your ipod, so if you're wandering around town, you can get out your iPod and there are your drink specials. The drinks specials integrate in the events calendar. *audience comment* Could you integrate the drinks specials with a GPS thing so drunk people could find their way to the bars? (laughter) That's a good idea. I hope you're getting the impression that everything kind of knows about everything else. It's one gigantic database. This example kind of events page (on a slide) - if an event happens at a bar, and the bar has a drinks special for the date the event is happening, it'll pull in the drinks special. If you go to this event, here's a drinks special for that place. Now living in Chicago, I really wish that MetroMix did something like this. Metromix... bad. So there's tons of cool data on this site, I'll go through a couple more things. The downloads page; we wanted to have kind of a front door for all the stuff you can download on this site, of course we can put random MP3's "here's a bunch of random MP3s", but that wouldn't be that exciting, so we were thinking - what would be a cool timely way of displaying MP3s as they're added to the site. This page, what it does, is it looks at the events calendar, it finds all the bands that are playing according to the events calendar in a local band database, and of those, which ones have MP3s. So everytime you go to this page, it's fresh, it's new, it's got new stuff according to who's playing, so everyone can get the MP3, get band information - oh, by the way, they're playing live at the . There's a mobile edition, so that when you're wandering around drunk in downtown Lawrence, you can pull up the drinks specials to further your alcoholism, you can see which restaurants are open right now, and you can get a bunch of other stuff that kind of makes sense to have in a cellphone context. There's blogs, there's podcasts, there's comments on everything, there's other stuff that I didn't want to offend anyone with (slide says 'pictures of drunk sorority girls')... especially, why am I bringing this up? The point is, you kind of have to understand the intensity of all the cool shit we did in Lawrence, and that was kind of our unofficial motto - we build cool shit - we wanted to do cool stuff, we wanted to put it on really rapidly, improve these sites - we'd get these ideas, like, on the events calendar you can sign up to get reminders of an event - that just happened one day when somebody told me 'hey, did you know that you can send SMS via email?' 'oh, I didn't know that, let's add it to the site' 'ok, let's do it today'. My boss calls me on a Saturday night "Hey, oh here's this cool idea for the site, why don't we do it?" and I'm like "hey, I'm at the computer anyway, I'll just do it right now". So that's the kind of culture. Where does this come from? Well it's this guy - Rob Curly - he was our boss there, and he really encouraged this really really rapid web development. It's essentially web development - computer programming - with journalism deadlines. It's a fusion of those two concepts. The first thing that he is really really pushing on us is that we need to develop things very very quickly. An example of that is, toward the end of last year, around the elections, he said: "Hey, oh my God, I just realised there's a presidential debate tonight. Wouldn't it be cool if users could sign on to our news site and rate the candidates. Wouldn't it be cool if people could rate candidates on whether they made sense, how eloquent they were, whether they made any weird facial expressions. Oh, and by the way, if you could do it in four hours, please". So, this kind of culture... first of all, it drove us insane. Secondly, it really encouraged us to come up with some sort of solution that would let us make websites - first of all that were very intense and cool and interactive and all that - but also so that we could do it quickly. The second thing - we did end up making that presidential debate score card in four hours - it was Jacob, who's doing AV stuff today. The second thing that he's always pressing on us was that the ink was never dry on these babies. A newspaper term, of course, ink being a newspaper thing, but the concept is that you create a web application of some sort, of course you have to create it quickly, that's the first point I had, but once you create it, the thing's not done yet. Inevitably, requirements change, you're going to have to change that thing to add new features, more ways of browsing, more ways of searching, all that stuff. The restaurants thing I showed you, for example, when that first started, it was just type of food and location of town. All those other things, including barter - barter I just added one night when I was futzing around - but all those other things were ideas that our editors had - oh, wouldn't it be cool if on our restaurants page you could search by whether they accepted Visa or American Express - so boom, the ink is never dry on these things. You've got to be able to not only make the first version very quickly, but you've got to be able to update them very very fast. So. We originally used PHP for this, the original version of Lawrence.com was a PHP app which started out OK, but it got quite messy. The problems with PHP were that the syntax is very verbose, you had to edit a lot of files to get stuff done, I know in theory it is possible to do good PHP, but it's just so much of a hassle - the language doesn't encourage good practise. Introspection abilities were very bad, you couldn't really follow the Don't Repeat Yourself principle, because you had to put bits in this file, and this in this file, and it was hard to maintain. And then there's the namespace thing (slide of PHP functions) - this is, of course, for those of you that didn't get the joke, a list of the first 30 PHP functions that start with 'A', available in any PHP script, and I believe - what's the latest on PHP namespaces? It's going into 6, probably? ==== Discovered Python ==== So, Simon and I, around this point - it was around two years ago when we were getting a little tired of PHP, we discovered Python, and we just immediately fell in love. Essentially, we loved the terse syntax, we loved how you could introspect, we loved the dynamic abilities - So clean, and it encouraged best practices. We said OK, we have to do this, we have to move all web development to Python, because we're going to go fricken insane if we stay with this PHP. So, we decided to make this framework for our internal needs - I showed you this entertainment site we have, we have a news site, a sports site, and our organisation does development for outside companies - so kind of a lot of different types of stuff that we do. So this framework that we were putting together had a couple of goals. One, like, I hope I've been pounding into your brain, we really had the need to make web development stupidly fast. Like four hours, not six months, fast. Like two days for an intense classified system. Jacob just this past week wrote an entire classified system between 9pm and 3am. No doubt powered by a lot of coffee, or something. We wanted to automate the repetetive stuff; there are certain tasks in web development that are just so frickin boring, like validation routines, and making sure that input is clean and all this stuff - we just wanted the framework to take care of this for us. We wanted to practise loose coupling, so that if we didn't like a certain part of this system, we could swap in another template language, we could swap in another database abstraction layer. We wanted to follow best practices - Simon and I, we developed this originally, are obsessive perfectionists. We really really strongly believe in the foundation principles of http - that everything that affects data on the server should use POST, that you use GET properly, beautiful URLs, because doing ugly urls is just pathetic. We wanted it to be efficient. We didn't want this to be some sort of really high level framework that did a lot of cool stuff, but didn't care about the efficiency. We needed it to be fast, we're powering more than a million page views per day, so if it doesn't need to do a database query, don't do a fricken database query. Be efficient. The end goal was that we wanted to create lawrence.com with this framework. ==== Starting to create the framework ==== When we created the framework, we kind of had a trial by fire, because we had a bunch of websites that we were creating as we were creating the framework, so we had to take a break, then go back to the framework, take another break, then go back to the framework. Essentially, the end goal though was to make lawrence.com. So, one of these trials by fire was when Rob came up to us and he said "Hey, it's summer, that means it's time for little league." and he had this wacky idea - why don't we take local little league, which is about a hundred... more than two hundred teams or something like that, and treat these teams like they're the New York Yankees. So I'm thinking every team gets it's own page (see slides) with a list of who they're playing, what field they're at, game info - tied into our local weather database, so if a game's in the next five days, which is the time range for which we have weather forecasts, it'll pull in that weather forecase and display it right on there. Why don't we give every league of L.L. it's own page, which what teams are in it, what the standings are. We didn't want to do player detail pages because of privacy reasons, but if these guys were 18, you know we would have been doing that. We wanted to have a database of every field that these guys play on. Because there are incredibly subtle differences between 4H east and 4H middle, but you can go on the site, and click on there, and do a little 360 degree view thing... if you care. And of course, we wanted to make it so that parents could sign up for cellphone alerts, so that if games were cancelled the website would email them. And of course, do this in three days. So, we did. Using Django, this was the first really big thing that we did - and it worked, and we were like "Wow, this is really really cool, we should use this". And we did, we continued to use it, and we ended up recreating lawrence.com to use it. lawrence.com is now powered by that, our news site ljworld.com is powered by it, all of our internal sites that our company had and all our commercial development that we did for other companies. So, let's fast forward a couple of years to PyCon 2005. If you don't know, this is a Python conference that's held every year. Simon and I, and also our other developer Jacob Kaplan-Moss, who's handling AV, went there, and we did a short lightning talk. It was five minutes, showing off Django and what it does and how fast it makes things. And people were just going gaga over those things. A lot of people came up to me afterward, I got a lot of emails afterward, so we were thinking 'wow, we should open source this' - not only because it's going to be a cool service to contribute back to the community, but because it would get outside developers giving us code. So, you know, it's kind of a win-win. So we did, we open sourced it in July. This is the Django website, it's at www.djangoproject.com, I''ll have that URL later also. Since July, we've had a ton of awesome contributions, people have been using it, people all over the world - Poland, Australia using it - it's awesome. So what does this actually do? ==== Django More Technical Discussion and Examples ==== I've kind of given a lot of background, but haven't actually talked code. There's the stack. Number one is the database wrapper - now what this does is it converts Python code into SQL, so you don't have to write SEQUEL statements. I'm going to alternate my usage of SQL and SEQUEL to please both camps, let's see if I can keep that straight. The second level is the URL dispatcher, which, because we're obsessed with clean URLs, and because we mix and match different applications on different sites - for example on Lawrence.com we have a forums system - and on our new site we have a forums system, but they have different URLs in different places, so the URL logic had to be abstracted into this URL dispatcher thing. There's a template system, which separates content from presentation; I think that's pretty much a well known concept. And there's the admin framework, which I think is pretty much Django's "crown jewel", which I will go over in a minute. That essentially automates all the boring ass stuff that's involved with validation and creating sites that are purely for editing stuff. Finally, there's a lot of niceities galore, such as RSS framework, and all these other things that I'll go into. Step 1: When you do a Django app, the first thing - assuming it's database driven, because it doesn't necessarily have to use a database - the first thing you do is you design your database schema. Now if we're going to do a sample application for the purposes of this, we'll do a little blog. It wont be written by a cat, but pretend it is (Slide shows Ginger The Cat's Blog). When you're creating generally a database driven app, the first thing you do is you create table statements. Create a table "blog entries" that has a headline varhcar entry, body, then the pub date. Well, in Django how you would represent that is, instead of in SQL, you would use a Python class. It looks very similar. The headline is just an attribute of that class, the body is another attribute and the pub_date is another attribute. Slide shows: {{{ class Entry(meta.Model): headline = meta.CharField(maxlength=50) body = meta.TextField() pub_date = meta.DateTimeField() }}} So that's it. All you need to do is write those 4 lines, and you get a whole heck of a lot of stuff free. First thing is, it generates the create table statement for you - if it didn't do that, it would really suck. The second thing is, it gives you a Python API to actually edit this information. So you don't have to write SQL statements. Here's how you would instantiate a headline object, pass int he headline, body and pub date: {{{ e = Entry(headline="Hello", body="Welcome to my blog", pub_date=date(2005,12,3)) e.save() # saves to DB }}} Pretty straightforward, I'm not writing any SQL. I can change attributes on it, save again, it will do the update statement intead of an insert. You can get stuff out of the database using this get_list API {{{ entry_list = entries.get_list() }}} You can pass parameters to get_list that specify essentially your WHERE clause - how you want to narrow down the search, such as just show me the entries with a certain pub_date, just show me the ones that have published=true, or something. You can get a particular entry out of the database like this: {{{ e = entries.get_object(pk=3) }}} Here I'm passing pk=3, the primary key is three, that would give me that entry. And, you just use attribute syntax to access the column values, so e.headline would display the headline. Note to purists: This does allow you to still drop into raw SQL if you want to - I hope you've got the impression that Simon and I, when we were desinging this, we're big perfectionists, and we know you have to drop into SQL if you need to. We don't want the framework to be something that gets in your way, we want it to be something that makes things super quick, so it's very easy to drop into SQL - and essentially in any part of this stack, you can drop down a level if need be. So, a lot of web development revolves around these admin forms, right. This is the piece of crap that I use to update my blog, that I wrote in PHP like five years ago, literally, and you know everyone who's a web developer has done this kind of thing - it's like, if you're a web developer you've made these. This is a tremendous pain in the butt, because we have to first of all display the form, we have to redisplay it with validation errors if there are any validation errors, you have to write the validation logic, and finally you have to do the logic that actually saves things. And that's just for adding. There's changing and deleteing too. Fortunately, with Django this is a solved problem, because we've abstracted it to a level where it will generate those forms automatically for you, in a production ready thing that we call the Admin site. To do that, here's the entry class I was showing you that represents a blog entry. If you want to give it admin capability, all you have to do is add this: {{{ class Entry(meta.Model): headline = meta.CharField(maxlength=50) body = meta.TextField() pub_date = meta.DateTimeField() class META: admin = meta.Admin() }}} Meta is an inner class that holds metadata about that. Admin is just one of many things you can put in there, it's just kind of a holding place for metadata. So just putting that line in, it will give you - boom - an admin site. This (see slide) is the admin site for the Lawrence operation, which has a ton of stuff. Essentially when you add that admin, it looks for all the objects in your system that have admin turned on, and displays links to them, it keeps track of your recent actions on the side, and it does authentication and all that stuff. Here's, for example, an add screen for a photo object - it knows, based on the database type, based on the field definition, what type of widget to use, so for example that first one there is 'photo', that when it was in the model was described in Python as a file field, it knows that file fields in a database is a textfield, and in the admin interface it's a little widget that is a file selector. For the second one there, it's a text field in the database, and it knows that it's a bigass text-area. The third thing, that's a many to many relationship, so for those it pulls in a multiple select box, and down there staff member is a many to one, so it puts in a little dropdown, and at the bottom, creation date - which I hope you can see - is a datetime field, and for any datetime field it automatically puts in the little date widgets, and you can click on the little today shortcut, and there's a calendar icon, and it pulls in a javascript calendar, and it's very exciting. So the point is, this is production ready, it just works and you don't have to hack with it, and you don't have to code all this logic. The really messy thing I mentioned about admin sites is the validation - well it automatically takes care of that for you. If I had submitted it empty, this is what I would have gotten (see slide). It knows which fields are required, because you specify that in your model. You keep every piece of domain logic in your model - that's the one true place that all metadata about your objects lives. One of those things is whether a field is required, one of those things is implicit in the type of the field, for instance date fields must be in a certain format, so the admin will validate that for you automatically, and of course you can add custom validators to your heart's content. Uh, the point with this is that it's completely production ready. The way we worked in Lawrence was that we would talk to the client - here's a client that we had (slide) Lawrence chamber of commerce, they wanted us to make a website for them, so we would talk to them, and they said "OK, let's put an accommodations thing, let's have a thing of all the local hotels, and the shopping malls and all that stuff so that people will come visit Lawrence". So, given that, we just coded up those models in half an hour, and we were able to give them an admin site which, one, blew their minds, and two, let them put stuff in there right away so they can start putting content in so that we can focus on doing the interesting things. Here's another site we did - a site for the attorney's association of Kansas, and this blue-jean clad website in Denver that was a local radio station - these are all examples of clients that we gave them the admin interface right away, they started putting data in, and we were able to work on it. Production ready. So, that let us focus on the interesting stuff. We haven't really written much code thus far, we've just written those four lines of the model that describes the data. The next thing you do, when you write a Django app is you design your URLs. We don't want this kind of stuff - we don't want to put .php, .cgi, and we don't want annoying query strings with question marks and scary characters. We don't want to expose the underlying framework in the URLs, because that's evil. We don't, we especially don't want to do this: foo.com/bar/site_view/pageinfrastructure/0,2545,TCP__16736__4285088,00.html Which I believe is and is disgusting. It's very very ugly. So, how it works in the Django framework is you specify it in pure Python code. This is what's called a URLconf - a URL configuration where you just... it's essentially a mapping between URLs and their callbacks. So in this example: {{{ }}} if anyone goes to '/blogs' it will call the Python function myapp.blog.homepage. If anyone goes to '/blogs/archive', it will call the archive. In the last example, it displays the capability of capturing things from the URL, so if you go to blog/archive then any number - that's just simple regular expression syntax - it will pass that as a parameter to the function myapp.blog.permalink. Let's take one of these for example: {{{ ('^blog/archive/(\d+)/$, 'myapp.blog.permalink') }}} This was the last one on that screen. That will call the function: {{{ def permalink(request, entry_id): return HttpResponse("Hello World") }}} That takes entry_id, which is whatever was captured in the url, and it returns HttpResponse. This is a view function. Views get, as their first argument, a request object which has all sorts of metadata about the request, like what browser it was, GET and POST data, what URL it was, and all that, and entry_id was taken from the URL. A view is essentially responsible for returning a HttpResponse object, which can be anything you want - it can be HTML, it can be plain text, it can be a PDF, it can be CSV, you can generate images, anything you want. But this is really really lame and boring, so let's beef it up a little bit. This is what the code would look like if you actually wanted to implement this. {{{ def permalink(request, entry_id): e = get_object_or_404(entries, pk=entry_id) return render_to_response('blog_permalink', {'entry': e}) }}} The first line there is get_object_or_404, you pass it your model module, and you tell it which parameters to use - so use the entries and get the object whose pk id is whatever number was passed in the URL, save that in the variable e, then you render to a response object using the blog_permalink template, passing it entry as the template context. I'll get to the template context in a little bit. A very little code, but it does a lot. I'll also mention for those of you that are in PHP or anything in those scary worlds, you don't have to worry about quoting database, you don't have to worry about SQL injections, because entry_id is quoted for you by the backend database, so it makes things - it just takes care of things for you. What does the template look like? I'll go back a bit - we loaded the blog_permalink template and passed it one variable, 'entry' - that last part is a dictionary for those guys who don't know Python, that's essentially a hashtable where entry is the name of the variable in the template, and e is whatever you want that variable's value to be. So the template would look like this: {{{

{{ entry.headline }}

Posted on {{ entry.pub_date }}

{{ entry.body }} }}} You put the headline between H1's, then Posted On, and whatever the pub_date is, and the entry body. It's a very simple template language, and yet very very powerful, and it does not allow Python code execution. It's intended to be designer friendly. Part of our philosophy is that the designer isn't - doesn't need to be a programmer as well. He shouldn't have to deal with Python code, and he shouldn't have to deal with the security issues of writing pure Python code. However you can write custom tags that let you do other assorted logic with the pure power of Python if you want to. That's basically the stack - models, URLs, views - which are those functions - and templates. Any one of these pieces of the stack can be swapped out for something else because it's all very loosely coupled. What else do you get with this framework? The first really really big contribution from the community after we open sourced it was internationalisation - so that any app in Django can automatically handle the language setting from browsers, so that if your browser is configured to use Polish, or you want to send out Polish things, it provides a framework for specifying translation strings. I don't know if anyone here deals with i18n, but it's very very handy. Already we have 19 translations of the Django admin, and it's really a trip for the hell of it to go in there, and change your browser language to French or Icelandic, and see the admin work in a different language. It's really really cool. And the cool thing about it is that we have Welsh! I don't think any other open source project... that's probably an exadgeration, but we have Welsh, so I'm really excited. Another thing is the cache system, because we're really really interested in performance. You can cache objects on a very granualar low level way - you can cache pages, or you can cache your entire site. I'm about to launch my first Django app at Washington post, and that's going to be using the entire site-wide cache, because it's like four million records, and it's a high-traffic site. So the cache system in that case was as easy as adding a single line that says "use cache=true". It doesn't actually say that, but essentially it does. There's authentication. The admin site that I showed you gives you free authentication, users and permissions, and you can have groups, and assign permissions to groups, and all that. But you can use it outside of it if you want to - you're not tied to using it - you're not tied to using the admin site if you don't want to anyway. There's anonymous sessions, handy for shopping carts, and all that stuff. There's an RSS admin framework that shouldn't even be legal, because it makes you - it's like this amount of code, and you have RSS feeds for everything. It's very very cool. Then there's the concept of generic views. That blog_permalink think I showed you, that was a view - but there are certain patterns in web development that can be abstracted at an even higher level. That was a good example - display a template rendering some object from the URL. So with Django you can step, even one step back, and not have to write any Python code at all - you just, in your URLconf, you point to a generic view function, and you tell it "I'm using the blog object" and it will automatically do everything for you. The only thing you have to do is write the template. We really find ourselves, when we do Django, focusing on the user interface and the templates, because there is no code to write. ==== What sites are using Django? ==== What sites are using this? I did a little side project - chicagocrime.org - if any of you guys live in the city, use this and become scared. It's a freely browsable database of crimes reported in Chicago, it's updated every day - you can go to a city block level, browse by date, street, all this stuff. It was slashdotted a couple of times. As a result of the first time, that's when we wrote the cache framework. But after that, it er, it held up very well. Here's an example of AJAX with Django, the crime map, you can specify which crimes you want to look for, it automatically updates the map ... sexy. There's this Polish - the Polish version of friendster - grono.net - has... it was a big Java shop, and they have converted a couple of pages on their site to use Django, and they've said that it's revolutionised things. For one, it's fun to write code again, because Python kicks ass. For two, the amount of code goes from this (indicates large quantity) to this (indicates small quantity). And the performance is better. So I don't know why you wouldn't do this. Just announced this week is a site of Greenpeace which is doing this cool new thing using Django, so that I'm interested in finding out more about, myself. So, if you like this, if you like what you're hearing here, you can put one of these guys on your site ("I wish this site were powered by Django" button/logo/image). I have one on my site because it's still running that PHP abombination. This actually was requested from the community, believe it or not. The community is really cool. ==== Concluding Remarks ==== I'm just going to close with a couple of quotes. "I've played more with Django, and grown to love it more with every passing day. I'm desperately looking for someone to pay me to build something with Django, and if it doesn't happen soon, I'm just going to go on strike" - James Bennett. "I've spent a few hours re-dunking my head in the Django soup. That is one impressive open source prjected... that shows (or at least seems to show!) that the people who designed it really knew what they were doing. It feels like opening up an iPod box and admiring the packaging, design, button layout." - David Ascher, author of "Python Cookbook" "I'm starting to rewrite the CCIW website with Django, and I'm amazed at my progress" - Luke Plant "And I will migrate my PHP stuff to Django and such frameworks in the future. PHP's braindead decisions by its developers has annoyed me a bit too much by now" - asmodai "Time to write a todo list webapp? 16 mins" - Bill de hOra "ever since I laid eyes on Django, I knew one day I'd be running my website off this web framework" - alastair "Conclusion: Django makes life easier" - Espen Grindhaug So, I invite you to check it out, it's at Djangoproject.com, and very very cool, and that's about it. So thank you very much for attending.