Week 2: “I'll send you a link”

There's a saying, All programs evolve until they can send email.1 Our Django application is certainly no exception, and in my second week I wanted to send an email to new users. And I wanted that message to include a link back to the web site.

No problem. People must do this all the time, right? Just pop a url tag into the template, and … ah, no, that's not a fully qualified URL, that's just the path. Alright then, we are using the Sites framework, so that'll fill in the … well, it does know the domain, but mysite.example.com/ still isn't an absolute URL, where's the protocol?

I guess the only two real options are http and https — the site doesn't run over FTP or Gopher, and nobody publishes SPDY links — so we'll just check the settings for something that tells us if this site is expected to use HTTPS, and … oh. There's no such setting.

Look, I understand that Django is not the web server, it is not actually opening port 80 or 443, and if the content is being served over an encrypted connection, it's not Django that is doing the encrypting. That's a perfectly reasonable separation of responsibilities. But having the web site be able tell you its own address does not seem like an unusual thing to ask.

It seems Simon Willison agrees with me, or at least he did in 2008, when he wrote this page about replacing get_absolute_url. That page says it is something we should re-think for Django 1.1, but I failed to find any more recent evidence of that making it in to Django core.

It is, of course, easy enough to define one's own PROTOCOL variable in the settings file and use that in my own template functions, but I think that there would be benefit if there were a standard, consistent way of generating links to the site.

But Kevin, you may say, you act as if it's impossible to get a link to your Django site, but that's simply not true! Why, I sent myself a link to the site through the password reset function in the auth framework just the other day!

Yes, of course, there are places in django core that use absolute URLs. There must be, for you can't even send a valid HTTP 1.0 redirect without one. So how is that done?

The password reset view checks the is_secure method on Request, which is a great thing to do if you're redirecting a browser that's already on the site, or even sending an email to a user who's just submitted a form. But if you're sending a message to anyone else, i.e. you aren't currently handling a request from the intended recipient of the message, you don't have that option.

  1. This was cited as Letts' Law when Jeff Atwood quoted it in 2007, but I haven't found a reference. It doesn't appear in the Jargon File or FOLDOC. Elsewhere it's attributed to a Richard Letts, though I'm not sure who that was — presumably not the Australian music advocate, although you never know.

    The earliest citation for the related Law of Software Envelopment I've found is Greg Kuperberg's post to rec.humor.funny in 1989.