Published in 19:48 of 08/11/2012 by

Published in 19:48 of 08/11/2012

←Home

Custom validator for web2py forms

web2py allows us to write custom form validators, by pattern validators in web2py are UPPERCASE

Hi Pythonista! I know that you are now wondering why does not follow PEP8 name convention? Ok, this is the web2py way, it breaks PEP8 a bit, but it has a good reason The naming convention is for preventing conflicts between objects named form and FORM helper class

Validators templates

There are two types of validators

  • VALIDATOR: It validates if some data is valid or if follow some pattern

  • TRANSFORMATION; It only takes the entered value and returns the transformed value

The patterns

class VALIDATOR(object):
    def __init__(self, error_message="SOMETHING WRONG"):
        self.error_message = error_message

    def __call__(self, value):
        error = None
        # CONDITION COMES HERE
        if "ERROR":
            error = self.error_message

        # IF error != None - value is invalid 
        return (value, error)

class TRANSFORMATION(object):
    def __init__(self, search, replace):
        self.search = search
        self.replace = replace

    def __call__(self, value):
        error = None
        try:
            # TRANSFORMATION COMES HERE
            value = value.replace(self.search, self.replace)
        except:
            error = "Not possible to transform"
        return (value, error)

How to write my own validator

Follow the patterns above, lets see some example

Validate if a zip-code starts with "051"

By some reason our system does not allows registering from other regions out of "051" zip code

class IS_ALLOWED_ZIP_CODE(object):
    def __init__(self, zip_area, error_message="Zip code not allowed"):
        self.zip_area = zip_ares
        self.error_message = error_message

    def __call__(self, value):
        error = None
        value = value.strip()
        if not value.startswith(self.zip_area):
            error = self.error_message
        return (value, error)

Now you can use this in your models

db.define_table("address",
    ...
    Field("zipcode", requires=IS_ALLOWED_ZIP_CODE("051"), notnull=True)
    ....)

Simply like that! now your forms will fire the "Not allowed Zip Code" when users tries to input a zip code as "04509-890"

Transform some text

class REPLACE_TEXT(object):
    def __init__(self, search, replace):
        self.search = str(search)
        self.replace = str(replace)

    def __call__(self, value):
        error = None
        try:
             value = value.replace(self.search, self.replace)
        except:
            error = "Error replacing"
        return (value, error)

In the same way you now replace values in your forms
Example: User enters latitude, longitude with "," and you replace with "."

replace_comma_with_dot = REPLACE_TEXT(",", ".")
db.define_table("address",
    Field("latitude", requires=replace_comma_with_dot),
    Field("longitude", requires=replace_comma_with_dot)
)

HOW IT WORKS?

web2py forms and DAL validate_and_* methods has a step where it takes all values in requires list
for every field in the table, so it takes the entered value and do a call to the validator class
as you can see, the validator implements the __call__ magic method, which means that it will execute when
the instance of the class are called. Yes, instances are callables

class Foo(object):
    def __call__(self, *args):
        print("I've been called with some args %s" % str(args))

>>> foo = Foo()
>>> foo("web2py", "rocks")  # we are calling the instance directly
I've been called with some args ('web2py', 'rocks')

also, is it possible to do some validation and transformation using compute for fields and form events as onvalidation and onaccepts

Thats it!

  • O Natal Animal 2013 está no ar in Home · 23:24 of 12/10/2013
  • Desenvolvendo protótipos para startups com Python e web2py in web2py · 20:25 of 11/19/2013
  • Gravando logs de aplicativos web2py in web2py · 00:29 of 01/21/2013

  • comments powered by Disqus Go Top