8 Reasons Why You Should Try Django

January 6, 2010

django

I have been using Python for quite a few years, but mostly for writing one off sysadmin scripts, command line utilities, and of course PyRadio. Most of my web development work has been done with PHP. The language gets a lot of bad press, some deserved and some not so much. I’ve had my own gripes, but all-in-all I’ve been fairly happy with PHP.

Several months ago, though, I thought I’d give Django a try, a python based web framework. I was completely blown away!  Compared to the PHP frameworks I’d worked with, such as Cake, it was just so much more of a pleasure to work with. So here are 8 reasons why you should give Django a try yourself if you haven’t already. You won’t be disappointed!

1. Great Documentation

The Django documentation is well written, extremely comprehensive, and up to date. The official documentation contains details API references, loads of relevant examples, and tutorials for those getting started. If that isn’t enough there’s also a whole book that’s available for free online.

2. It’s Python

The fact that it’s Python is a huge plus point for me. It’s a great language that doesn’t suffer from many of the well documented inconsistencies that PHP does, and includes some nice features such as decorators and first-class functions. Going back to PHP you soon start to miss the little things, such as the ability to assign multiple values at once, and the simplicity of slicing lists.

3. The ORM

Django’s object relational mapper completely abstracts away the database, meaning you don’t need to worry about your database schema or constructing SQL queries. If you’re using to writing SQL queries then the QuerySet API takes a little getting used to, but it’s really worth the effort. Projects like South make the ORM even more powerful, allowing you to make schema changes and data migrations automatically.

4. Built in Development Server

Where PHP really shines is on its ease of deployment. Setting up a local development server can be a bit of a pain though, especially if you’re working on several different sites. Django comes with a built in development server though, so you can be up and running within minutes! From your project’s root directory you just do

./manage.py runserver

and access your django website from http://localhost:8000 – awesome!

5. The Admin Interface

Django’s built-in admin interface is practically a full blown CMS, allowing you to add, delete or update your data. It’s pretty much all automatic, but it’s also fairly configuration. See the documentation to see what it can do!

6. Reusable Applications

Django projects are broken up into “applications”, and there are lots of existing reusable applications that you can use for your own projects, such as those for user registration, facebook integration, blogging, and many many more.

Existing applications are great, but the whole project/application distinction also forces you to think about your own project structure and therefore more likely to make reusable components that you can use in more of your own projects, or even share for others to use.

7. Templates

I’ve always been a bit dubious about the merits of PHP template engines such as Smarty. The Django template layer is great though. The inheritance model works well, and the restrictive language really forces you to have a very clean separation of presentation and logic.

8. Forms

I usually find dealing with user input one of the most boring parts of web development. It takes time to get it right, and its repetitive. The Django Form API really simplifies things. You can define your form class, include and validation rules, and simply add a few lines to your template and few lines to your view and you’re done!


So those are my 8 reasons why you should give django a go. If you’re already a django user let me know if you have any points to add!

Faking late static binding in PHP

November 18, 2009

PHP 5.3 brings lots of long awaited features to the language, including closures, late static binding and namespaces. Unfortunately 5.3 still isn’t widely available, so some of us are stuck with older version of the language that lack these great new features.

One feature I miss all the time is late static binding, or LSB. The lack of LSB means that you can’t tell tell which class in your class hierarchy was invoked when calling a static method. Here’s a simple example:

class class0 {
  public static function getName() {
      echo __CLASS__ . "\n";
  }
}

class class1 extends class0 {}

class class2 extends class1 {}

class0::getName(); // -> "class0"
class1::getName(); // -> "class0"
class2::getName(); // -> "class0"

Notice that all three method calls output “class0″, the name of the base class. There is no way to tell which class the static method was called on, and in some situations that is information we need to know.

So what can we do? One obvious solution is to re-implement the method in every subclass. This doesn’t pose much of a problem for a method as simple as the one in our example, but in reality our method is likely to be much more complex, and implementing it in every subclass will lead to lots of duplication. If we ever need to make changes to the method then changes will need to be made to every subclass too. Not fun!

And alternative solution is to have every subclass invoke the parent method, passing in the class name (or whatever variable we’re interested in). It requires only a couple of extra lines per subclass, rather than repeating the whole method. Any changes now only need to be made in one place. Here’s the code:

class class0 {
  public static function getName($class = __CLASS__) {
      echo "$class\n";
  }
}

class class1 extends class0 {
  public static function getName($class = __CLASS__) {
      return parent::getName($class);
  }
}

class class2 extends class1 {
  public static function getName($class = __CLASS__) {
      return parent::getName($class);
  }
}

class0::getName(); // -> "class0"
class1::getName(); // -> "class1"
class2::getName(); // -> "class2"

In PHP5.3 we can use the new get_called_class(), so the code becomes much cleaner:

class class0 {
  public static function getName() {
      echo get_called_class() . "\n";
  }
}

class class1 extends class0 {}

class class2 extends class1 {}

class0::getName(); // -> "class0"
class1::getName(); // -> "class1"
class2::getName(); // -> "class2"

PHP Error Log Mail Script

May 26, 2009

With the configuration option “log_errors” PHP will log all errors to the Apache error log file, allowing you to see all of the errors that have occurred while people have been using your site. Given the snippet of code below:

<?php
	// Ensure logging is enabled. Ideally this will be set in php.ini
	ini_set('log_errors', 'On');
	// Call a non-existant function to generate an error
	doesNotExist();
?>

You’ll see something like the following entry in the error log, which includes a description of the problem and the file and line number of where the problem occurred:


[Tue May 26 19:54:53 2009] [error] [client 127.0.0.1] PHP Fatal error: Call to undefined function doesNotExist() in /var/www/index.php on line 6

I’ve written a small bash script to mail me all of the PHP errors that it finds in the log. The results are sorted and piped through the “uniq” command to remove any duplicate errors. I’ve set it up to run as a cron task once a day, so if there are ever any problems it isn’t long before I know about them. The code is below:

#!/bin/bash
# Mail out PHP errors that are in the apache error log.
# Note PHP's log_errors must be turned on
# Ben Dowling - www.coderholic.com

errorLog=/var/log/apache2/error.log # Error log location
email=you-email-address@example.com # Send report here

# Pull out the lines that mention PHP, and use AWK to get the column we're interested in
errors=$(cat $errorLog | grep PHP | awk -F'] ' '{print $4}')
# Remove referer information, sort, and remove duplicate entries
errors=$(echo "$errors" | awk -F', referer' '{print $1}' | sort | uniq)
# Check that we actually have some errors
if [ -n "$errors" ]
then
	echo "$errors" | mail "$email" -s "PHP Errors"
fi

If you need to it should be quite easy to modify the script for a slightly different use, such as printing out all the fatal PHP errors that are in the log.

Hope you find it useful!

The Ultimate Scalability Presentation

April 29, 2009

At work we’re experiencing some fairly rapid growth, and our single production server is starting the feel the strain. I’ve been doing a lot of investigation into how we can scale the site, and thankfully there is lots of information out there.

The “Do you Scale” presentation I saw at PHP London a couple of months ago gave a good high level overview of scalability issues, and included some useful techniques to help you scale.

I think I’ve found the ultimate scalability presentation though: “Real World Web: Performance & Scalability”. The 189 slides contained within this presentation cover almost everything I’ve read elsewhere, and it’s packed full of practice advice!

Javascript, JSON and PHP

March 29, 2009

JSON data is commonly used as a simple way to send data back to client side javascript from the server. For example, a PHP script may output the following JSON to confirm that an action was taken:

{success: true, message: "It worked!"}

or in the case of failure:

{success: fase, message: "It didn't work!"}

Below is a basic javascript callback function to process the JSON data, displaying the returned message:

function callback(data) {
    if(data.success) alert(data.message);
    else alert('ERROR:' + data.message);
}

Sometimes it’s actually useful to send back javascript code to in the JSON data, to be run on the client. For example, if an Ajax request is made that updates some account information we could return javascript code to update several parts of the page with the new information. Here’s PHP code that outputs JSON data which includes javascript code:

$response = array('success' => 'true',
    'code' => "jQuery('#id').html('Success!');");
echo json_encode($response);
// Outputs {success: true, code: "jQuery('#id').html('Success!');"}

Note how in the returned JSON data “code” is actually a string, so it won’t be possible to run the code simply by doing “data.code()” on the client. Instead we must explicitly tell javascript to evaluate the string as code. Below is an example of how we can do this using eval:

function callback(data) {
    if(data.success && data.code) eval(data.code);
}

If we wanted to update the page with HTML more complicate the the simple “Success!” message in the previous example we must be careful to escape any quotes in the HTML correctly. If we wanted to set the content to: “Javascript”, “json”, “PHP” then we’d need to do the following:

$response = array('success' => 'true',
    'code' => "jQuery('#id').html('\"Javascript\", \"json\", \"PHP"');");
echo json_encode($response);

And It’s easy to imagine a far more complicated example. The code becomes less readable, and if you accidentally forget to escape one of the quotes, or escape of the quotes that shouldn’t be escaped, then the whole thing breaks. A nice alternative is ty store the HTML as a separate JSON property and then to reference it, avoiding the need to escape the quotes and making the code easier to read:

$response = array('success' => 'true',
    'html' => '"Javascript", "json", "PHP"',
    'code' => "jQuery('#id').html(this.html);");
echo json_encode($response);

However, to make the “this.html” reference work the clients side callback function will need to changed, as eval() runs the code in global scope. This means that “this.html” will refer to a global html variable rather than the one in our JSON data. We can get around this problem by using the apply function as follows:

function callback(data) {
    if(data.success && data.code) {
        var f = new Function(data.code);
        f.apply(data);
    }
}

And here’s a complete example which uses jQuery to perform the Ajax call:

jQuery.get('update.php', {} function(data) {
    if(data.success && data.code) {
        var f = new Function(data.code);
        f.apply(data);
    }, 'json');
Older Posts »