that.dork.jordan
Django CSRF headaches?

I spent hours upon hours today trying to figure out why the Django 1.2 CSRF system was not working for me. There are obviously a lot of struggles with existing Django installs in converting to 1.2 because of the CSRF protection, but none of my searches turned up a useful resolution for my particular problem. What I saw was the typical “CSRF verification failed” message but I’d installed the middleware and inserted the token and passed in RequestContext so it should have worked. Then I switched off my tornado server and tried it via Django’s built-in server and voila! It worked.

Django 1.2 works with the latest versions of Tornado (I’m now running 1.1) but if you have a very old version I suspect you may run into the same problem I did. Save yourself the headache and make sure tornado is up to date and you don’t have any old versions installed.

Share
Django Forms: Add to validation, don’t override. And how to require fields conditionally.

This picture of me is not at all relevant but often times the pictures I post are not...I’ve spent the past six months working on a lot of different projects but one of the biggest projects I’ve been working on is a back-end system for the company I work for. If you ever want a sure-fire way to begin eating, breathing, and sleeping in Python, try joining a start-up and building something like this from the ground up. Lucky for us, Django is around to make this sort of thing far less difficult.

One of the greatest features of Django is the built in form handling functionality. Define some fields, throw a variable at the template, and add a form tag and submit button and you are pretty much done. It even does all the validation for you. Well, sort of…

As all generic things go, the validation that Django does is, well, generic. It’s easy to override the methods that do the validation, but then you lose the original validation provided by Django. So what do you do when you want to add to the existing validation instead of replace it? It isn’t exactly documented but it is possible…

In this example we have a form with a field that is only required in certain circumstances. Everything else about the validation needed to be the same.

Define the form:

class CreditCardPaymentForm(forms.Form):
    mark_paid_in_full = forms.BooleanField(required=False)
    payment_note = forms.CharField(required=False)

In this form you will have a checkbox to mark the payment “paid in full.” What we want is to require a note when that checkbox is selected. I’ve omitted the rest of the form as it’s irrelevant for the example.

This is where the trickery comes in. We are going to override the clean() method, check if mark_paid_in_full is selected, and change payment_note to required if it is, then run the existing validation.

def clean(self):
if self.cleaned_data['mark_paid_in_full']:
    payment_note_field = self.fields['payment_note']
    payment_note_field.required = True

    try:
        super(forms.CharField, payment_note_field).clean(
                self.data['payment_note'])
        except forms.ValidationError, error:
            self._errors['payment_note'] = error.messages

    return self.cleaned_data

As you can see a few things happen here. First it’s important to know that self.fields will contain all the field objects. Then we try to call the CharField’s clean method. I won’t delve into the specifics of how super works as there are already many articles covering that topic but if you aren’t familiar with super, it’s worth reading about. Then if the clean method raises a ValidationError, catch it and put it in the _errors property. You could just as easily leave the ValidationError raised and Django would print the error message… albeit at the top of the form. In some cases this might be desirable, but here we want to actually tie those errors to the appropriate field. Finally, you should always return self.cleaned_data or you will get some truly bizarre results :)

if this is something you are trying to do I hope this saved some time.

Share
Longer Django usernames (using email addresses)

My new job involves a whole lot of Django development. While we were testing the first version of our new site just before launch we stumbled across an interesting limitation of Django: The included django.contrib.auth package limits usernames to 30 characters and this can not be over-ridden easily. Thirty characters may seem like a lot for a username but if you want to use email addresses as your login identifier it can easily become a problem. 

So I found myself in the office at 8pm digging through Django’s source code to find all the locations where the character limit is hardcoded in such a manner that it can not be overridden. There aren’t many but there are a few and it is honestly quite annoying that these values are hard coded. Eventually I’d like to contribute changes to the project that will allow you to change the limit more easily but for now I’ve attached a patch that can be used against Django 1.02 and will allow for up to 75 characters in the username.Django 75 character username limit patch

Applying is as simple as dropping the diff in the django/contrib/auth directory and running patch -R < django-75-char-username.diff

Django 75 character username limit patch

Share