Log in

Peter · of · the · Norse · Thinks · He’s · Smarter · than · You

He Might be Right

Recent Entries · Archive · Friends · Profile

* * *

I’m currently in the process of moving from Django 1.4 to 1.8 and Python 2.7 to 3.4. The main reason I’m writing this is so that someone else making the same changes doesn’t need to work too hard.

This is one of my gripes about the Django Foundation. They don’t consider that there will be a fair number of projects jumping from one long term support to another. Instead, they recommend going from 1.4 to 1.5 to 1.6 to 1.7 to 1.8. That ain’t fun. The only thing I was able to find is a Guide to updating to 1.7.

Upgrading Python from 2 to 3

Of course the first step to any change like this is creating a new virtual environment and branching your CVS. Since I’m moving to py3k, I’m going to use the built-in pyvenv. There are some arguments for using the good old virtualenv, but I’m trying to keep it as clean as possible.

You’ll want to make sure that you’re using the most up-to-date version of your DB and other support libraries. Update your requirements.txt so that it pulls the latest version of addons.

There’s a good guide to moving from Python 2 to 3. Since I’m not going to worry about backwards compatibility, I can just run 2to3 and rename all of the functions. You can’t do it first and then test because 1.4 doesn’t have any py3k compatibility, but it’s so simple that you can do it at almost any point.

Actually upgrading Django requires taking a look at 1.5, 1.6, 1.7, 1.8, and the deprecation timeline. This is what I call obnoxious. The entire point of writing this is so that we can consolidate all of the changes that need to be made in one place with simple language step by step directions. Let’s get into it.

Changes to settings.py

  • Templates is now a list of backends with some settings for each. While this isn’t necessary for right now, it’s going away in 1.11.
  • ALLOWED_HOSTS is now required
  • Many settings have been removed. Look through your settings file and find what they’ve been changed to.

Changes to templates

  • You can remove {% load url from future %}. If you haven’t been using it, then you need to update your {%url%} tags.
  • {%cycle%} and {%firstof%} now autoescape.

Changes to code

  • django.conf.urls.defaults is now django.conf.urls.
  • Everywhere that was query_set is now queryset.
  • Same with mimetype becoming content_type.
  • django.utils.simplejson is dead. You can just use the Python json instead.
  • ValidationError has a completely different format. If you were dealing with multiple errors, that’s changed.
  • ModelForms now require an explicit _Meta.exclude=().
  • Transaction management has completely changed. You’ll have to change most of it.

django.contrib sections removed

  • django.contrib.comments
  • django.contrib.gis.sitemaps
  • django.contrib.databrowse
  • django.contrib.localflavor
  • django.contrib.markup
* * *

The stuff that happened in the last post bothers me more than it should. The reason is poor timing. I figured all this out just before a brief bout of depression. (By brief, I mean less than a day.) For everyone who doesn't know (which is almost everyone), depression isn't "extra sad", it's "emotionless". (My own experiences with depression make Vulcans scary.) For about 5 hours, the only emotion I had was annoyance at Hangouts.

Over the course of those hours, the echo box of my otherwise empty emotional landscape intensified my feelings into blind rage. It's actually a bit scary. And this ball of hate is still with me. I've been working on it for months, but there's still a part of me that wants to work over the Hangouts team with a baseball bat. Yes, Google has screwed over it's customers, but that doesn't mean they deserve my hate.

* * *

I was forced to delete my Google+ account recently. The problem is it was interfering with work. My office has Gmail for Work because it’s cheaper and more reliable than Outlook. And it comes with several features too. We’re using Google Docs constantly, and alot of conversations in Google Talk. Or rather were. The problem is Hangouts. Everbody was upgraded to Hangouts, and it’s completly broken.

There are a shit ton of missing features: First, there are only two states: available and unavailable. XMPP has at least a half dozen: available, busy, away, idle, disconnected, mobile. And since Talk was built on XMPP, it meant you knew why someone wasn’t answering your IM. If the message was undeliverable, you were warned, but Hangouts claim that all messages will be delivered. This is a lie.

Second, it doesn’t use a “buddy” list. It will connect to anyone with a Google+ account. And the only identification is your name and photo.  So if there is someone who works at Google with the same name as you, you’re going to get a bunch of random IMs.

This hit the perfect storm at work. Since everyone has a personal account with the same name and a photo that matches, it’s impossible to tell if someone will get the message. I have never used Hangouts, but because I had logged into G+ on Chrome, and had not explictly logged out, I was showing up as “available”. I never saw any of these messages. I missed an important impromptu meeting because they contacted my private account.

So I tried to find out how to stop people from using my personal accout. I tried un-circling and blocking coworkers; that just made me “unavailable” as if I had logged out. The only way to remove myself of their list of contacts is to delete my account. And before you tell me that this is a lot of whinging for a free service, I’d like to remind you that my work account isn’t. In fact the problem only lies with the account that we are payng for.

This goes on the pile of things that make Google less useful to me. The new maps engine won’t let me save directions. Google docs no longer lets you save something as a template. Search no longer lets you know what’s an ad and what’s a search result until you mouse over. I’d rather not deal with them anymore, and have starting moving what I can away.

* * *

Yesterday was my birthday (I lied to Facebook), and that’s caused me to think about what the last year has entailed. I’d like you to humor me as I look back at what the past year of my life.

A typical day

Wake up, Breakfast, shower, etc.
Drive to work
More work
Drive home
Fix/eat dinner
Clean up the house
Struck with the sudden feeling that by throwing away and packing up my mother’s personal possessions, I’m intentionally forgetting her.
Eat junk food and watch television
Go to bed

I’m not sure what the cause is, but I’m suddenly nostalgic. Perhaps it’s a side effect of being in the mid-30s. I was seriously considering buying Now That’s What I Call Music of the 90s. If it weren't for Ace of Base being on it, I might have.

Hell, my company is moving to a new office a few blocks from my old high school, and when I passed it last weekend I wasn’t filled with rage at my time there. First time in 20 years.

* * *
I just heard one of my favorite bands in a commercial. Should I be happy that they’re getting money, or annoyed that the song was so butchered? It could be worse. Fans of Phillip Phillips must be pulling their hair out.
* * *
* * *

I was really looking forward to Tour de Fat this year. I even bought a glittering green cape for it. Ran into Aaron during the parade.

When I came back in the afternoon, I saw Aaron, but avoided him. I knew he was going to ask what happened to the cape. Why would you buy a glittering green cape and not wear it? I also knew the answer was “Things have changed since this morning”.

This is a problem. When things get tough like this, I retreat. I know I’m going to retreat even further in the coming days. Don’t let me.

* * *
I was passed by someone on a fixie.
* * *

My major Django project involves mixing Django urls with static. That is, I want /blog/ and /djpro/ to be handled by the same Python dæmon, but / to be the static file /html/index.html.

Turns out that’s not something you can do out of the box. mod_wsgi splits the url when you use WSGIScriptAlias and Django treats it as if you did an include in your URL. You can merge them together in your wsgi.py

from django.core.wsgi import get_wsgi_application
_application = get_wsgi_application()

# I found a thing at http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango
# that merges the PATH_INFO & SCRIPT_NAME.
def application(environ, start_response):
    environ['PATH_INFO'] = environ['SCRIPT_NAME'] + environ['PATH_INFO']
    environ['SCRIPT_NAME'] = '/'
    return _application(environ, start_response)

Then, all you need is to do is use multiple WSGIScriptAliases on the same WSGIDaemonProcess.

* * *

The last time I talked about tags in Django, there was only one game in town: Django-tagging. Now there is Django-taggit. It does (almost) everything right: A relation manager is used, which shows up in forms and the admin site. A slug is included. And it prefers commas to spaces as a delimiter. However, it wants to be user compatible with Django-tagging, so spaces can be used. Fortunately, that’s a simple problem to fix. I replaced the parse_tags and edit_string_for_tags functions, and it works great. Also, it’s case sensitive. I replaced the appropriate code so that it matches on the slug instead of the name. This has the added benefit of knowing that ‘hip hop’ and ‘hip-hop’ are the same thing.

You might not want to go that far, but if you’re using tags in Django, you should take a look at Django-taggit. It’s tagging done right.

* * *

Sometime something happens that we can’t see because the effected part is scrolled off screen. Most of the time it doesn’t happen because the button to trigger a DOM change is part of the DOM element. But sometimes something in another window or frame will change the main view. I first noticed the problem when I was testing adding a new line at the end of the playlist. The new div was added below the bottom of the window, so I couldn’t see it. The answer is to scroll the window to show the element. There are auto-scroll jQuery plugins out there, but they are designed to replace anchor links. I would make my own plugin, but my requirements are orthogonal to a typical use case.

The first step is to find the where the top and bottom of the line we want to see are.

jQuery.fn.showLine = function() {
    var line_top = this.offset().top;
    var line_bottom = line_top + this.outerHeight() + 18;

The 18px added to the bottom is for the height of the insert link. It overlaps the next line a little bit. I also add for the height of the postition: fixed header.

    var win_top = $(window).scrollTop() + 45;
    var win_bottom = win_top + $(window).height();

    if (line_top < win_top) {
        var new_top = line_top - 54;
    } else if (line_bottom > win_bottom) {
        var new_top = line_bottom - $(window).height() + 9;
    } else {

If any part of the line is scrolled off the top or bottom, then we find the nearest scroll amount that will show the whole thing, plus a little bit for padding. Finally, we animate the scroll.

    $('body, html').animate({scrollTop: new_top}, 400);

I use $(window) to find the value, because it always works. But it doesn’t animate. So I have to use both body and html because different browsers work differently. One will respond, and the other will simply ignore scrollTop.

Watch for my next post where I rave about django-taggit.

* * *
* * *