Login

UsernameField (for clean error messages)

Author:
davepeck
Posted:
August 6, 2009
Language:
Python
Version:
1.1
Score:
1 (after 3 ratings)

This is a username field that matches (and slightly tightens) the constraints on usernames in Django's User model.

Most people use RegexField, which is totally fine -- but it can't provide the fine-grained and user friendly messages that come from this field.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import re

from django import forms
from django.forms import ValidationError
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _

class UsernameField(forms.CharField):
    default_error_messages = {
        'username_too_short': _(u'Usernames must be at least three characters long.'),
        'username_too_long': _(u'Usernames can be at most thirty characters long.'),
        'bad_username_start': _(u'Usernames must start with a letter from the alphabet.'),
        'invalid_username': _(u'Usernames can only have letters, digits, and underscores.'),
    }
    
    MIN_USERNAME_SIZE = 3
    MAX_USERNAME_SIZE = 30
    
    def __init__(self, *args, **kwargs):
        super(UsernameField, self).__init__(*args, **kwargs)
        
    def clean(self, value):
        super_clean = super(UsernameField, self).clean(value)
        
        # We could do this all with one regular expression:
        #    ^[A-za-z]\w{1,29}$
        # but to be kind to our users we do it with increasingly 
        # restrictive tests that give increasingly more detailed error feedback.
        
        if len(super_clean) < UsernameField.MIN_USERNAME_SIZE:
            raise ValidationError(self.error_messages['username_too_short'])            
        if len(super_clean) > UsernameField.MAX_USERNAME_SIZE:
            raise ValidationError(self.error_messages['username_too_long'])        
        if re.match(r'^[A-Za-z]', super_clean) is None:
            raise ValidationError(self.error_messages['bad_username_start'])
        if re.match(r'^[A-Za-z]\w+$', super_clean) is None:
            raise ValidationError(self.error_messages['invalid_username'])
        return super_clean

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

diverman (on August 11, 2009):

Look at RegexField...

#

davepeck (on August 12, 2009):

diverman: You missed the point. :-)

Sometimes you've got to return precise, friendly error messages. This is especially true when you want your users to actually have a shot at signing in. You could use a RegexField, and if it doesn't validate you could always display the same error message regardless of the root cause. Or you could use this class to get easier to understand fine-grained error messages for entered user names.

RegexField is not the solution to all the world's woes -- especially where human factors are involved.

#

Please login first before commenting.