Passo-a-Passo web2py, 5º Passo

No 4º passo entendemos o funcionamento do CRUD e como aplicá-lo no web2py. A partir disso, conseguimos compreender melhor o funcionamento do SQLFORM, inclusive para realizar edição de registros; a utilização de querys, para selecionar registros; e o método de deleção.

Segue o índice para que você acompanhe também os outros passos:

Dessa forma, hoje devemos nos aprofundar em mais opções do web2py que utilizam esses mesmos conceitos ou algo bem semelhante. Tudo pronto?

Usando aquela velha expressão de “matar dois coelhos com uma cajadada só”, nós vamos nos aprofundar em vários conceitos de uma vez só. Para isso, vamos imaginar a seguinte situação:

Eu estou visualizando todos os filmes que eu tenho na minha locadora na página de filmes. Porém, neste momento, minha locadora tem muitos filmes. Assim, fica difícil eu encontrar um filme específico quando estou olhando entre tantos registros.

Para conseguir visualizar esse filme, eu teria que filtrar os registros que estou selecionando, mas seria muito difícil se eu tivesse que alterar meu código toda vez que eu quisesse filtrar filmes diferentes. Além disso, exibir todos os filmes de uma vez me faz ficar completamente perdida na página de filmes, o que só dificulta mais o trabalho.

Lista de Filmes

Lista de Filmes

Assim, temos dois problemas para resolver:

  1. Precisamos de uma forma de buscar por filmes específicos;
  2. Precisamos melhorar a exibição de filmes;

Realizando buscas

Vamos começar implementando uma solução para a pesquisa de filmes. A primeira coisa que devemos fazer é receber o filme que o usuário está procurando. A forma mais fácil de fazer isso é receber os valores que o usuário passa pela URL, nosso meio de comunicação básico. Por isso, vamos receber o filme pelas variáveis, dessa forma:

http://seudominio.com/locadora/default/ver_filmes?filme=Procurando Nemo

Sendo filme a nossa variável e Procurando Nemo o valor associado a ela, podemos montar nossa query de seleção a partir disso. Dessa forma, temos o seguinte código:

def ver_filmes():
    if request.vars.filme:
        filmes = db(Filmes.titulo == request.vars.filme).select()
    else:
        filmes = db(Filmes).select()
    return dict(filmes=filmes)

 

Como vimos antes, o request.vars funciona como um dicionário que armazena variáveis da URL. Dessa forma, chamando request.vars.filme, estamos solicitando o valor da variável filme.

Com o  if-else acima exibiremos o filme pesquisado sempre que ele for passado na URL ou todos os filmes quando nenhum for passado. Note que, caso não seja encontrado nenhum valor como o que você passou na URL, não será exibido nenhum filme.

Busca por semelhança

Ainda que a busca esteja funcionando como deveria, ela está muito rígida. O nome precisa ser exatamente como o que colocamos na URL, ou a nossa busca não funcionará. Por isso, podemos fazer a seguinte modificação:

def ver_filmes():
    if request.vars.filme:
        filmes = db(Filmes.titulo.like('%'+request.vars.filme+'%')).select()
    else:
        filmes = db(Filmes).select()
    return dict(filmes=filmes)

O método like() da nossa query seleciona apenas filmes com o título semelhante àquele que estamos informando.

Colocamos as strings com % para o web2py identificar onde pode ocorrer aquela semelhança. Ou seja, se colocamos % antes da palavra pesquisada significa que pode ter qualquer coisa escrita antes da ocorrência da palavra que pesquisamos, já o % depois da palavra pesquisada significa que pode ter qualquer coisa escrita depois da ocorrência da palavra que pesquisamos. Colocando os dois, pode ter qualquer coisa antes ou depois da palavra pesquisada.

Se pesquisamos, por exemplo, por ‘procurando’ apenas, ele identifica o filme Procurando Nemo por semelhança.

Pesquisa de filme parcial

Pesquisa de filme parcial

Views

Nossa busca está muito melhor e nós facilitamos bastante a vida do usuário. Porém, ainda é incômodo para o usuário ficar pesquisando filmes pela URL. Para ele, o melhor seria utilizar um formulário onde ele pudesse escrever o termo que ele procura e clicar em um botão para pesquisar. Por isso, vamos começar a manipular nossas views para que isso seja possível.

No web2py, as views são os arquivos de exibição de informação e pode estar em vários formatos, como html, json, xml, etc. Nós iremos utilizar apenas as views em formato html para alterar as visualização da nossa página de filmes por enquanto.

Para começar a editar a nossa view da página ver_filmes, temos que localizá-la. Para isso, vamos navegar até a pasta views da nossa aplicação. Lá, veremos que existem outras views e uma pasta chamada default.

Pasta views

Pasta views

O web2py roteia as views por seus controllers. Portanto, toda página que estiver definida dentro do controller default.py deve ter sua view dentro da pasta default que está na views. Além disso, cada view é identificada por seu nome. Ou seja, se o nome da nossa página é ver_filmes, o nome da view deve ser ver_filmes.html.

Se você acessar a pasta default, não encontrará nenhuma view chamada ver_filmes.html. Isso ocorre porque estamos usando a view genérica, então não temos uma view específica para a nossa página ainda. Por isso, vamos criá-la.

Crie um novo arquivo html chamado ver_filmes.html dentro da pasta default. Feito isso, quando tentar abrir a página de visualizar filmes novamente, verá que não aparecerá nada. Isso porque acabamos de sobrescrever a view da página e ela não tem nenhum conteúdo, então não existe para ser exibido mesmo.

Para vermos as coisas mais parecidas com o que estava antes, vamos editar a view com o seguinte conteúdo:

{{extend 'layout.html'}}

<h1>Ver Filmes</h1>

{{for filme in filmes:}}
    {{=filme}}
{{pass}}

Primeiro vamos entender o que está escrito aqui e depois vamos entender o que aconteceu na tela de visualização.

A primeira linha do nosso código possui algumas informações entre chaves duplas ({{ }}). Nas views do web2py, todo conteúdo dentro dessas chaves deve ser entendido e executado como código Python. Neste caso, estamos pedindo pro web2py estender uma view chamada layout.html, que é uma view padrão do web2py que contém esse estilo do bootstrap presente no framework, além do menu e do footer.

Além disso, como você vê nas linhas de código que seguem, todo bloco de código (ifs, fors, whiles, etc) devem ser encerrados com a palavra pass. Isso porque você não precisa indentar seu código Python que está nas views, então você deve informar de alguma maneira quando o bloco termina.

Por último, as chaves duplas com o sinal de igual ({{= }}) funcionam como um comando print. O que estiver dentro dessas chaves será exibido na tela do usuário.

Concluindo, tudo que fizemos nessa view foi colocar um título (<h1></h1>) e exibir, linha por linha, os filmes que selecionamos do banco de dados. Lembre-se que, quando terminamos a nossa função ver_filmes(), retornamos um dicionário ao final:

def ver_filmes():
    if request.vars.filme:
        filmes = db(Filmes.titulo.like('%'+request.vars.filme+'%')).select()
    else:
        filmes = db(Filmes).select()
    return dict(filmes=filmes)

E é essa variável filmes retornada que nós iteramos na view e exibimos filme por filme.

Mas, ainda que alterando a view, a exibição não está como antes. Agora, cada filme aparece como uma tag <Row>. Isso ocorre porque o web2py imprime todo o objeto na tela, ou seja, como temos um registro do tipo Row (linha) do banco de dados, ele o exibe dessa forma mesmo. Para deixar a visualização mais bonita, podemos criar uma tabela. Usarei apenas dois campos como exemplo:

{{extend 'layout.html'}}

<h1>Ver Filmes</h1>

<table>
  <thead>
    <tr>
      <th>Título</th>
      <th>Diretor</th>
    </tr>
  </thead>
  <tbody>
    {{for filme in filmes:}}
    <tr>
      <td>{{=filme.titulo}}</td>
      <td>{{=filme.diretor}}</td>
    </tr>
    {{pass}}
  </tbody>
</table>

A visualização está cada vez melhor. Agora, tudo que precisamos é de um formulário para buscar filmes!

{{extend 'layout.html'}}

<h1>Ver Filmes</h1>

<form action="" method="post" class="pull-right">
  <input name="filme" placeholder="Pesquisar" />
  <input type="submit" value="Pesquisar" />
</form>

<table>
  <thead>
    <tr>
      <th>Título</th>
      <th>Diretor</th>
    </tr>
  </thead>
  <tbody>
    {{for filme in filmes:}}
    <tr>
      <td>{{=filme.titulo}}</td>
      <td>{{=filme.diretor}}</td>
    </tr>
    {{pass}}
  </tbody>
</table>

Vamos entender o que está acontecendo agora.

A primeira coisa que fazemos é criar um formulário e ele irá funcionar da seguinte forma: quando pressionarmos o botão para pesquisar, ele vai enviar o valor que digitamos no campo para algum lugar e lá faremos qualquer tipo de validação que desejarmos com essa valor.

Mas como e para onde esse valor será enviado? É isso que respondemos com os atributos method e action do nosso form.

O atributo method significa o que iremos fazer com o valor digitado no campo de pesquisa. Para entender melhor sobre os métodos que podemos utilizar, sugiro que faça uma pesquisa sobre http methods, pois se trata de muito conteúdo para discutirmos aqui. De qualquer forma, o método post que escolhemos é o que indica que nosso valor será enviado para algum lugar.

O atributo action é o que informa a página que irá receber esse valor. Como deixamos esse atributo em branco, significa que esse valor deve ser enviado para a mesma página em que estamos. Ou seja, é a função ver_filmes que irá receber o valor.

E como iremos receber esse valor na nossa função ver_filmes?

O método post faz, basicamente, a mesma coisa que estávamos fazendo. Ele vai enviar variáveis com os valores que passamos no nosso formulário, porém ele vai fazer isso de forma não tão visível, pois essas variáveis não irão aparecer na nossa URL.

Para saber o nome das variáveis que iremos receber então, basta verificar o nome dos inputs. Por exemplo, o nosso input que recebe o nome do filme recebe um atributo name=filme, ou seja, o nome da variável referente a esse campo será filme. Assim, nem precisamos mudar o nosso request.vars para receber o valor da pesquisa desse formulário.

Portanto, se tentar fazer uma pesquisa agora, verá que ela está funcionando sem nem mesmo precisarmos mexer no código da nossa página ver_filmes(). Isso porque continuamos recebendo a variável com o mesmo nome para fazer a pesquisa.

Grids

Agora que aprendemos como fazer tudo isso na força bruta, tenho uma novidade: poderíamos ter feito tudo isso de forma quase automática, gastando menos linhas e usando menos recursos. Tudo isso devido a um elemento do web2py chamado Grid, que é um facilitador que o web2py oferece para organizar a exibição de dados.

Vamos tentar utilizá-lo. Substitua o conteúdo da sua página no controller por:

def ver_filmes():
    grid = SQLFORM.grid(Filmes)
    return dict(grid=grid)

E o conteúdo da view por:

{{extend 'layout.html'}}

<h1>Ver Filmes</h1>

{{=grid}}

A SQLFORM.grid() recebe a tabela do seu banco de dados da qual você quer exibir os registros e cria uma tabela html bem organizada para isso. Ela também traz um campo de pesquisa no qual é possível você pesquisar por registros. Ou seja, ela teria nos poupado muito trabalho, mas foi importante aprender sobre tudo aquilo, não foi?

SQLFORM.grid exibindo os filmes

SQLFORM.grid exibindo os filmes

Nós podemos personalizar a grid de diversas maneiras, como exibir apenas campos específicos ou mesmo ativar as funções de edição e deleção, para que sejamos capazes de editar ou deletar os registros a partir dela, além de várias outras funcionalidades. Você pode saber mais sobre a grid na aqui na documentação do web2py, caso tenha interesse.

Conclusão

Terminamos por aqui hoje. Conseguimos aprender todo um fluxo de buscas, a personalizar views e a fazer tudo isso ainda mais rápido com a grid.

Nossa aplicação já está bastante avançada e em breve devemos concluí-la. Não deixe de acompanhar os próximos passos!

Anúncios

13 comentários sobre “Passo-a-Passo web2py, 5º Passo

  1. Geovane Anderson disse:

    Boa tarde Júlia,

    Parabéns pela iniciativa e muito bom o seu material e didática! Acompanha você em outros sites e deixe à você, o meu desejo de muito sucesso.

    Júlia, no passo 5, este código está certo?


    def ver_filmes():
    if request.vars.filme:
    filmes = db(Filmes.titulo.like(‘%’+request.vars.filme+’%’)).select filmes = db(Filmes).select()
    return dict(filmes=filmes)

    Nota: Não deveria existir um parenteses após a palavra “select”?

    Felicidades

    Curtir

    • Newton Galiza disse:

      Deve ter ocorrido algum erro na digitação.

      O código correto fica o seguinte:

      “””

      def ver_filme():
      if request.vars.filme:
      filmes = db(Filmes.titulo.like(‘%’+request.vars.filme+’%’)).select()
      else:
      filmes = db(Filmes).select()
      return dict(filmes=filmes)
      “””

      Curtir

  2. Denival Jeter Guimarães disse:

    Estou com um problema. Não sei se estou fazendo algo errado ou se é um bug do web2py.
    Eu chamo um grid em um pagina assim:
    def consulta():
    if(request.vars.id_tb is None):
    id_tb = session.id_tb
    else:
    id_tb = request.vars.id_tb
    extra_links = [
    lambda row:A(‘Detalhes’,_class=”btn btn-primary”,_href=URL(“default”,”detalhes”,args=[row.dia,id_tb]))]
    query = ((db.tabela.id_tb==id_tb))
    grid = SQLFORM.grid(query=query,fields=[db.tabela.dia, db.tabela.campo2, db.tabela.campo3], create=False, deletable=False, editable=False, csv=False, searchable=False, selectable=False, details=False, user_signature=True, links=extra_links, paginate=9999)

    E de cada linha deste grid, tenho um botão (graças ao extra_links), para leva a outra página, contendo um grid com os detalhes referente a cada linha e que estão numa tabela2
    E faço assim para os detalhes:
    def detalhes():
    dia = request.args(0)
    id_tb = request.args(1)
    query =((db.tabela2.dia==dia and db.tabela2.id_tb==id_tb))
    grid = SQLFORM.grid(query=query,fields=[db.tabela2.dia, db.tabela2.detalhe], create=False, deletable=False, editable=False, csv=False, searchable=False, selectable=False, details=False, user_signature=True, paginate=9999)
    return dict(form=form,grid=grid)

    Quando clico no botão “Detalhes” não abre a página dos detalhes e é redirecionado imediatamente para a pagina da consulta novamente, Se modifico a variável grid, tirando o SQLFORM.grid e substituindo por exemplo por grid = ‘X’ a página dos detalhes abre normalmente e fica nela, não sendo redirecionado.
    Acredito que haja algum conflito na montagem do grid, já que a função SQLFORM.grid foi utlizada da página de consulta, e ao chamar a página de detalhes a função é acionada novamente.

    Alguma idéia?

    Curtir

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s