Yes, that's exactly what you do. In Django 1.4 (the latest), they store passwords using PDKDF2 or bcrypt. The nice thing is that it automatically upgrades the hash function if it used to be something else:
_______
Password upgrading
When users log in, if their passwords are stored with anything other than the preferred algorithm, Django will automatically upgrade the algorithm to the preferred one. This means that old installs of Django will get automatically more secure as users log in, and it also means that you can switch to new (and better) storage algorithms as they get invented.
So it would be trivial for the big sites to have switched transparently to a safer hash, even if MD5 was Ok when they started. You could also add salts in the same way, if you were storing unsalted hashes.
In regards to "what to do with the existing hashes" bcrypt can detect the original work factor and hash to that. Not sure how you would upgrade that for users, however.
Couldn't you just move from, say, using MD5(password) to bcrypt(MD5(password))? So when it becomes apparent that the old hash is no more secure, start using the combination of the old bad hash (MD5) and the new good hash (bcrypt). This way you can simply run once through the password database, hash each password hash there with the new better hash, and throw away the old hashes. No need to prolong the process until the users log in.
They have some older APIs that depend on MD5(password) being used directly, to compare against auth credentials or to derive other hashes to verify API requests.
Though older APIs they're still used by many older or infrequently updated clients, such as hardware devices with sold with Last.fm integration.
Unfortunately, the longer you've been around the more likely you are to develop dependencies that make it more difficult to upgrade your password hashing.
A new site can do whatever it wants with password hashing, but it becomes harder for older sites with more legacy dependencies to make that kind of change and Last.fm has been around for almost 10 years.
This isn't to say "MD5 is cool, don't worry", but to try and illustrate some of the reasons behind this.
As hashing functions aren't injective, composing them leads to a reduction of range (ie, a smaller set of possible output values). As such, (bcrypt . MD5) would almost certainly be a weaker hash than bcrypt alone. Might not be enough to make a difference, but I'd consult a cryptologist before betting on that.
Yeah, it would be weaker against a collision attack. But that shouldn't be a concern as the purpose of the password hashing function is to protect against a preimage attack: finding the password given its hash. I can't see how the composition could be more vulnerable to a preimage attack than its parts. (Provided that the inner function's output is evenly distributed.)
Great feature. So you alter the password field (extending the length) if needed and when a user signs in it gets auto-updated and Django always tests both/all specified algorithms? Or do you have to add a new database field when moving on? (Sorry for my tl;dr behaviour but while I've got an expert on the line anyway...)
I'm not an expert in any sense, just a Django user. I've never actually looked under the hood, since it just works.
You specify an order of the hash algorithms, putting the one you want first. Switching to bcrypt for me was just a matter of moving it up a few lines in a list.
The password field can probably stay the same length, since it is a hash value anyway. I'm assuming you have a second field that stores the hash algorithm used. When it logs you in, it uses the current algorithm to authenticate you. Then if that technique isn't first on your list, it creates a new, salted hash, and stores both that and the new hash type in the database. Nice and slick.
_______
Password upgrading
When users log in, if their passwords are stored with anything other than the preferred algorithm, Django will automatically upgrade the algorithm to the preferred one. This means that old installs of Django will get automatically more secure as users log in, and it also means that you can switch to new (and better) storage algorithms as they get invented.
https://docs.djangoproject.com/en/dev/topics/auth/#password-...
_________
So it would be trivial for the big sites to have switched transparently to a safer hash, even if MD5 was Ok when they started. You could also add salts in the same way, if you were storing unsalted hashes.