5dollarwhitebox.org - theboxownsyou

  • blog
  • projects
  • articles
  • tech wiki
  • about
  • login
Home › Python: Unique Username, Groupname, Email Validators for TurboGears 2.0 Form Widgets

RSS Feed

Reply to comment

Python: Unique Username, Groupname, Email Validators for TurboGears 2.0 Form Widgets

drks — Thu, 2009-12-31 00:34

Disclaimer: This is a rough brain dump. I plan on doing a proper hello world in the near future, but wanted to get this somewhere accessible so I didn't forget about it.

I came across a rather annoying issue of how to properly handle duplicate usernames, groupnames, and email addresses in turbogears 2. What I came up with was a set of validators that can be added to chained_validators on your form validation. I'm using the dMirr project as an example of how I'm using these validators:

dmirr/widgets/validators.py:

import re
import pylons
from pylons.i18n import ugettext as _
from formencode import Invalid
from formencode.schema import SimpleFormValidator
from tw.forms.validators import Email
 
from dmirr.model import DBSession as db
from dmirr import model
 
__all__ = ['UniqueEmail', 'UniqueUserName', 'UniqueGroupName']
 
def validate_unique_email(value_dict, state, validator):
    # first for edit forms
    if value_dict.has_key('user_id'):
        u1 = db.query(model.User).filter_by(user_id=value_dict['user_id'])\
             .first()
        if u1.email_address != value_dict['email_address']:
            u2 = db.query(model.User)\
                 .filter_by(email_address=value_dict['email_address']).first()
            if u2:
                return {'email_address':'The address already exists.'}
    # or new form                
    else:
        u1 = db.query(model.User)\
             .filter_by(email_address=value_dict['email_address']).first()
        if u1:
            return {'email_address':'The address already exists.'}
 
 
def validate_unique_user_name(value_dict, state, validator):
    # first for edit forms
    if value_dict.has_key('user_id'):
        u1 = db.query(model.User).filter_by(user_id=value_dict['user_id'])\
             .first()
        if u1 and u1.user_name != value_dict['user_name']:
            u2 = db.query(model.User)\
                 .filter_by(user_name=value_dict['user_name']).first()
            if u2:
                return {'user_name':'The user name already exists.'}
    # or new form        
    else:
        u1 = db.query(model.User)\
             .filter_by(user_name=value_dict['user_name']).first()
        if u1:
            return {'user_name':'The user name already exists.'}
 
def validate_unique_group_name(value_dict, state, validator):
    # first for edit forms
    if value_dict.has_key('group_id'):
        g1 = db.query(model.Group).filter_by(group_id=value_dict['group_id'])\
             .first()
        if g1 and g1.group_name != value_dict['group_name']:
            g2 = db.query(model.Group)\
                 .filter_by(group_name=value_dict['gropu_name']).first()
            if g2:
                return {'group_name':'The group name already exists.'}
    # or new form                
    else:
        g1 = db.query(model.Group)\
             .filter_by(group_name=value_dict['group_name']).first()
        if g1:
            return {'group_name':'The group name already exists.'}
 
UniqueEmail = SimpleFormValidator(validate_unique_email)
UniqueUserName = SimpleFormValidator(validate_unique_user_name)
UniqueGroupName = SimpleFormValidator(validate_unique_group_name)



The easiest way to use this is to add the validator to your chained_validators under your form widget.

dmirr/widgets/user_form.py:

"""User Form"""
 
import re
from pylons.i18n import ugettext as _
from tg import config, url
from tw.api import CSSLink
from tw.forms import TableForm, TextField, TextArea, CheckBox, Spacer, \
                     HiddenField, PasswordField, Label, SubmitButton, Button
from tw.forms.validators import Schema, Int, NotEmpty, UnicodeString, \
                                FieldsMatch, Email, URL        
 
from dmirr.widgets.validators import UniqueEmail, UniqueUserName
 
 
class DynamicLabel(Label):
    value = ''
    template = 'dmirr.widgets.templates.dynamic_label' 
 
class UserNewForm(TableForm):
    css = [CSSLink(link=url('/theme/%s/_css/user.css' % config['theme']))]
    validator = Schema(
        chained_validators=[
            FieldsMatch('email_address', 'confirm_email'),
            FieldsMatch('password', 'confirm_password'),
            UniqueEmail(),
            UniqueUserName(),
            ]
        )
    fields = [
        TextField('user_name', label_text='User Name', help_text="This can not be changed.", 
            validator=UnicodeString(not_empty=True)),
        TextField('display_name', label_text='Display Name',
            validator=UnicodeString(not_empty=True)),
        TextField('web_url', label_text='Web URL',
            validator=URL(not_empty=False)),    
        Spacer(),
        TextField('email_address', label_text='Email Address',
            validator=Email(not_empty=True)),
        TextField('confirm_email', label_text='Confirm Email'),
        Spacer(),
        PasswordField('password', label_text='Password',
            validator=UnicodeString(not_empty=True)),
        PasswordField('confirm_password', label_text='Confirm Password'),
        Spacer(),
        TextArea('about', label_text='About/Description'),
        Spacer(),
        TextArea('terms', label_text='Terms of Use'),
        CheckBox('agreed_to_terms', label_text='Agree to Terms', 
            help_text="Check if you agree to the terms of use.",
            validator=NotEmpty),
        ]
    submit_text = 'Register User'
 
class UserEditForm(TableForm):
    css = [CSSLink(link=url('/theme/%s/_css/user.css' % config['theme']))]
    validator = Schema(
        chained_validators=[
            FieldsMatch('password', 'confirm_password'),
            UniqueEmail(),
            UniqueUserName(),
            ]
        )
    fields = [
        HiddenField('user_id', validator=Int()),
        HiddenField('user_name'),
        HiddenField('_method'),
        #TextField('user_name', label_text='User Name',  
        #    validator=UnicodeString(not_empty=True)),
        DynamicLabel('user_name', label_text="User Name", suppress_label=False),
        TextField('display_name', label_text='Display Name',
            validator=UnicodeString(not_empty=True)),
        TextField('web_url', label_text='Web URL',
            validator=URL(not_empty=False)), 
        TextField('email_address', label_text='Email Address',
            validator=Email(not_empty=True)),
        Spacer(),
        PasswordField('password', label_text='Password',
            validator=UnicodeString(not_empty=False)),
        PasswordField('confirm_password', label_text='Confirm Password'),
        Spacer(),
        TextArea('about', label_text='About/Description'),
        SubmitButton('submit', attrs=dict(value="Save User")),
        Button('Cancel', attrs=dict(value="Cancel", onClick="history.back();"))
        ] 
 
create_user_form = UserNewForm("create_user_form", action=url('/user/'))
edit_user_form = UserEditForm("edit_user_form", action=url('/user/?_method=PUT'))



You can see that I use both the standard Email validator in the widget, and also the new UniqueEmail, UniqueUserName validators in the chained_validators. All that is required is a hidden 'user_id' field in your form so that the validator can look up the current values in the database to compare against.

‹ Python: Setting up a TurboGears Application Under Shared Namespace up Python: Getting Started with setuptools ›
  • Printer-friendly version

Reply

The content of this field is kept private and will not be shown publicly.
Input format
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <bash>, <c>, <cpp>, <diff>, <drupal5>, <drupal6>, <java>, <javascript>, <mysql>, <perl>, <php>, <python>, <ruby>. Beside the tag style "<foo>" it is also possible to use "[foo]".

More information about formatting options



Who's online

There are currently 0 users and 2 guests online.
  • blog
  • projects
  • articles
  • tech wiki
  • about
  • login

5dollarwhitebox.org is not responsible in anyway for actions performed based on information found on this site.