terça-feira, 18 de setembro de 2012

Validadores no Web2py

Depois de criar formulários, é preciso garantir que os dados que serão inseridos neles são confiáveis. Para esta finalidade contamos com os validadores (validators). Basicamente,  os dados inseridos no formulário serão aceitos apenas se atenderem às exigências estabelecidas pelos validadores.
Como de costume, o Web2py oferece diversas soluções prontas e a possibilidade de implementar nossas próprias. No Livro você encontra uma seção especial sobre validadores.
Agora vamos ver o que podemos fazer com validadores.
Para começar, vou utilizar o exemplo do formulário criado no post sobre SQLFORM.
O formulário é criado no controlador default.py:
def contatos():
    form = SQLFORM(db.contatos, submit_button='Salvar', 
               fields=['nome', 'email'])
    if form.process().accepted and completarCadastro(form.vars.id):
        response.flash = 'Contato cadastrado!'
    elif form.errors:
        response.flash = 'Erro ao cadastrar! Verifique os dados.'
    return dict(form=form)

Na view default/contatos.html temos apenas:
{{extend 'layout.html'}}
{{=form}}

No modelo definimos a tabela contatos:
db.define_table('contatos',
Field('nome', 'string'),
Field('email', 'string'),
Field('dtcadastro', 'date'),
Field('status', 'string', requires=IS_IN_SET(['Ativo', 'Inativo'])))


Note que o campo status possui um terceiro argumento "requires". Não é dificil entender a sua função. É o argumento requires que recebe o(s) validador(es) do campo. Neste exemplo, usamos o validador IS_IN_SET(). Este validador recebe uma lista de valores como argumento e retorna erro caso se tente inserir no campo um valor que não esteja na lista definida. Em resumo, o campo status pode receber apenas os valores Ativo ou Inativo.

Agora, ao acessar a página default/contatos.html desta aplicação, o formulário que veremos é semelhante a este:
Se eu clicar no botão Salvar sem preencher o formulário os dados serão salvos sem erros. E ao acessar o banco de dados o último registro inserido contém a data e o status que são definidos pela própria aplicação, já os campos nome e email estão em branco. Este comportamento não está correto e devemos evitar que um registro sem identificação de nome seja criado. É aí que entra o validador mais básico.
Vamos alterar a linha do modelo que define o campo nome da nossa tabela contatos:
Field('nome', 'string', requires=IS_NOT_EMPTY()),

E agora se pressionarmos o botão Salvar sem preencher nada o resultado será semelhante a este:
E nenhum registro novo será criado no banco de dados.
Novamente, é bem simples perceber o que este validador faz. Quando definimos o atributo "requires" de um campo para IS_NOT_EMPTY(), fazemos com que o preenchimento dele seja obrigatório em cada novo registro que criarmos. Por isso, se tentarmos deixar o campo em branco no formulário, o registro não será criado e uma mensagem de erro padrão será exibida, como na imagem acima. Este validador possui um argumento opcional bastante útil. Observe:
Field('nome', 'string',
      requires=IS_NOT_EMPTY(error_message='Campo obrigatório')),

E o resultado é:
O argumento "error_message" permite personalizar a mensagem de erro que a aplicação irá exibir caso algum dado não seja corretamente validado.

Mais Validadores

Veja outros exemplos de validadores úteis:

IS_LENGTH()
Para limitar o comprimento de dados inseridos em formulários.
requires=IS_LENGTH(45) # Dados com 45 caracteres ou menos
requires=IS_LENGTH(minsize=4) # Dados com 4 caracteres ou mais
requires=IS_LENGTH(15, 4, error_message='Senha deve ter de 4 a 15 caracteres!')

IS_INT_IN_RANGE()
Para limitar o valor de um número dentro de uma faixa específica:
requires=IS_INT_IN_RANGE(0, 120, error_message='Você não pode ser tão velho!') 

No exemplo acima, o valor deve estar entre 0 e 119 (120 exclusive).

IS_EMAIL()
Verifica se o dado inserido tem as características de um endereço de email.
requires=IS_EMAIL(error_message='Email inválido!') 

IS_LOWER() e IS_UPPER()
Estes validadores não retornam erro, apenas convertem o valor do campo para letras minúsculas (lower) ou maiúsculas(upper).

Estes são apenas alguns exemplos. Para mais exemplos de validadores consulte o Livro do Web2py.

Validadores de Banco de Dados

Todos os validadores que vimos até agora podem ser definidos em uma instância do objeto Field, ou seja, um campo de uma tabela de banco de dados. Mas também podem ser definidos diretamente em um widget de formulário, como os utilizados pelas classes FORM() e SQLFORM.factory().
Porém existem validadores muito úteis que se utilizam de dados específicos de campos de tabelas de bancos de dados.
O validador IS_NOT_IN_DB() serve para evitar a inserção de dados duplicados em um campo, semelhante a uma chave primária.
Veja um exemplo alterando a linha do campo email no modelo:
Field('email', 'string', unique=True, requires=IS_NOT_IN_DB(db,
          'contatos.email', error_message='Este email já está cadastrado')),
Caso você tente inserir no campo email do formulário um valor que já está nesta tabela, a aplicação retornará a mensagem de erro que definimos. Desta forma, garantimos que o mesmo email não seja cadastrado duas vezes.
Note que para este exemplo também adicionei o argumento unique=True ao campo. Este argumento não é obrigatório para que o validador funcione. No entanto, é aconselhável sempre utilizá-lo pois assim evitamos que dados submetidos simultaneamente possam passar pelo validador, ao nível de processamento do formulário, e serem criados no banco de dados.

Outro validador de banco de dados muito útil é o IS_IN_DB(). Previsivelmente, sua lógica de funcionamento é a oposta à logica do validador anterior.
O IS_IN_DB() permite que um dado seja inserido em um campo apenas se ele existir em outra tabela do banco de dados, semelhante a uma chave estrangeira. Este validador é útil, por exemplo, se tivermos uma outra tabela no banco de dados com uma lista de emails de contatos que têm permissão de acesso a atualizações da aplicação. Desta forma, podemos limitar o cadastro de contatos do nosso exemplo apenas aos emails que já estão inseridos naquela tabela.
Veja o exemplo:
#Nova tabela criada para o exemplo
db.define_table('teste',
Field('email', 'string'))

#Alguns dados inseridos para o exemplo
db.teste.insert(email='email1@dominio.com')
db.teste.insert(email='email2@dominio.com')

#Linha alterada na tabela contatos
Field('email', 'string', unique=True, requires=IS_IN_DB(db,
          'teste.email', error_message='Este email não está cadastrado')),
O resultado será semelhante ao mostrado na imagem abaixo:
O widget do campo no SQLFORM é automaticamente alterado para uma dropbox, onde o usuário deve escolher uma das opções disponíveis. Neste caso, as opções são os emails da tabela teste que criamos.
No próximo post vamos ver como criar nossos próprios validadores para funções específicas em nossas aplicações.

Nenhum comentário:

Postar um comentário