Log in |
Construir uma lista de itens e preços (zclass e zcatalog)It's a portuguese how-to teaching about zclasses and zcatalog. It's based on kedai " How-To: Build a simple ZClass ", but not is an translation. O produto em questão foi desenvolvido por Thiago e Hélio para a Escola de Veterinária da UFMG. O objetivo era criar uma lista de itens e preços que pudesse ser pesquisada e que fosse facilmente administrada. ConsideraçõesAssumimos que você tem bom conhecimento do Zope, sendo desnecessária a explicação minuciosa dos passos apresentados. Utilizamos Zope 2.3.2, em um sistema operacional Linux, para o desenvolvimento. Versões anteriores não devem ser problema, entretanto. MetasAo fim desse Como-Fazer, teremos um objeto PrecosFolder, que guardará objetos PrecosItem, e um catálogo desses itens. Teremos também um método para apresentar os itens e seus preços numa tabela, bem como um formulário de busca e um método para apresentar os resultados em um ou mais PrecosFolder. O que faremos:
1. Criar as classesEm 'Control_Panel/Products', adicione um novo produto ('Add Product') com Id "PrecosFolder" e Title "Lista de Preços". Dentro do produto PrecosFolder recém criado adicione uma nova zclass. Preencha com "PrecosFolder" o Id, o Title e o Meta Type. Para que a nova classe possa conter objetos, selecione 'ZClasses:ObjectManager' como classe base. Certifique-se para que as opções 'Create constructor objects?' e 'Include Standard Zope persistent object base classes?' estejam marcadas. Clique em 'Add'. Você terá criado a classe PrecosFolder e seus construtores. Entre na classe PrecosFolder que você criou e adicione, novamente, uma zclass. Preencha Id, Title e Meta Type com "PrecosItem". Deixe marcadas as opções 'Create constructor objects?' e 'Include Standard Zope persistent object base classes?'. Selecione 'ZCatalog: CatalogAware' como classe base. Isso permitirá que PrecosItem seja indexada pelo catálogo que iremos criar na instância de PrecosFolder. Clique em 'Add'. Como resultado você obterá a seguinte estrutura: 2. Adicionar propriedades personalizadasDentro da classe PrecosFolder, clique na aba 'Property Sheets' e em 'Add Common Instance Property Sheet'. Preencha o Id com "PrecosFolder" e clique em 'Add'. Entre na recém criada folha de propriedades PrecosFolder e adicione o seguinte:
Dentro da classe PrecosItem, de forma semelhante à ilustrada acima, adicione o seguinte à folha de propriedades PrecosItem da classe PrecosItem:
3. Modificar os scripts de construção de PrecosFolderTudo o que precisamos fazer é modificar o formulário e o método que constroem o objeto para que as propriedades sejam adequadamente preenchidas e para que um zcatalog seja criado automaticamente. 3.1. Editar as propriedadesSubstitua o conteúdo de PrecosFolder_addForm por: <html> <head><title>Adicionar PrecosFolder</title></head> <body bgcolor="#FFFFFF" link="#000099" vlink="#555555"> <h2>Adicionar PrecosFolder</h2> <form action="PrecosFolder_add"> <table> <tr> <th>Id</th> <td><input type="text" name="id" /></td> </tr> <tr> <th>Titulo</th> <td><input type="text" name="title" /></td> </tr> <tr> <td colspan="2"> <input type="submit" value=" Adicionar " /> </td> </tr> </table> </form> </body> </html> Agora vamos modificar o método inicial para que o objeto tenha o título que foi incluído no formulário. Substitua o conteúdo de PrecosFolder_add por:
<html>
<head><title>Adicionar PrecosFolder</title></head>
<body bgcolor="#FFFFFF" link="#000099" vlink="#555555">
<dtml-with "PrecosFolder.createInObjectManager(REQUEST['id'], REQUEST)">
<dtml-call "propertysheets.PrecosFolder.manage_editProperties(REQUEST)">
</dtml-with>
<dtml-if DestinationURL>
<dtml-call "RESPONSE.redirect(DestinationURL+'/manage_workspace')">
<dtml-else>
<dtml-call "RESPONSE.redirect(URL2+'/manage_workspace')">
</dtml-if>
</body>
</html>
Explicando: 3.2. Criando um zcatalogAdicione o seguinte código a PrecosFolder_add no primeiro
<dtml-call "manage_addProduct['ZCatalog'].manage_addZCatalog('catalogoItens','',
'create_default_catalog_',REQUEST)">
<dtml-with "catalogoItens">
<dtml-call "manage_delColumns(['summary',],REQUEST,RESPONSE,URL1)">
<dtml-call "manage_addColumn('nome',REQUEST,RESPONSE,URL1)">
<dtml-call "manage_addColumn('preco',REQUEST,RESPONSE,URL1)">
<dtml-call "manage_addIndex('nome','TextIndex',REQUEST,RESPONSE,URL1)">
</dtml-with>
4. Modificar os scripts de construção de PrecosItemPrecosItem exige uma abordagem mais complicada. Para facilitar a administração, optamos por criar Ids automaticamente a partir do nome dado ao item. Como usamos acentuação e o Id precisa ser compatível com o padrão para URLs, fizemos um script para retirar todos os acentos e caracteres não padrão. Além disso, no ato da inclusão, editaremos as propriedades do objeto e o incluiremos no zcatalog. 4.1. Criar um Id automaticamenteVamos criar um script python chamado "ide" dentro da classe PrecosFolder, para que possa ser utilizado pelo método PrecosItem_add. Preencha 'Parameter List' com "nome" e o corpo do script com:
id=''
dicionario={' ' : '_', '!' : '_', '"' : '_',
'#' : '_', '$' : '_', '%' : '_', '&' : '_',
'\'' : '_', '(' : '_', ')' : '_', '*' : '_',
'+' : '_', ',' : '_', '-' : '_', '.' : '_',
'/' : '_', '0' : '0', '1' : '1', '2' : '2',
'3' : '3', '4' : '4', '5' : '5', '6' : '6',
'7' : '7', '8' : '8', '9' : '9', ':' : '_',
';' : '_', '<' : '_', '=' : '_', '>' : '_',
'@' : '_', 'A' : 'a', 'B' : 'b', 'C' : 'c',
'D' : 'd', 'E' : 'e', 'F' : 'f', 'G' : 'g',
'H' : 'h', 'I' : 'i', 'J' : 'j', 'K' : 'k',
'L' : 'l', 'M' : 'm', 'N' : 'n', 'O' : 'o',
'P' : 'p', 'Q' : 'q', 'R' : 'r', 'S' : 's',
'T' : 't', 'U' : 'u', 'V' : 'v', 'W' : 'w',
'X' : 'x', 'Y' : 'y', 'Z' : 'z', '[' : '_',
'\\' : '_', ']' : '_', '^' : '_', '_' : '_',
'`' : ' ', 'a' : 'a', 'b' : 'b', 'c' : 'c',
'd' : 'd', 'e' : 'e', 'f' : 'f', 'g' : 'g',
'h' : 'h', 'i' : 'i', 'j' : 'j', 'k' : 'k',
'l' : 'l', 'm' : 'm', 'n' : 'n', 'o' : 'o',
'p' : 'p', 'q' : 'q', 'r' : 'r', 's' : 's',
't' : 't', 'u' : 'u', 'v' : 'v', 'w' : 'w',
'x' : 'x', 'y' : 'y', 'z' : 'z', '{' : '_',
'|' : '_', '}' : '_', '~' : '_', ',' : '_',
'^' : '_', '*' : '_', '-' : '_', '-' : '_',
'~' : '_', '¡' : '_', '¢' : '_', '£' : '_',
'¤' : '_', '¥' : '_', '¦' : '_', '§' : '_',
'¨' : '_', '©' : '_', 'ª' : '_', '«' : '_',
'¬' : '_', '' : '_', '®' : '_', '¯' : '_',
'°' : '_', '±' : '_', '²' : '_', '³' : '_',
'´' : '_', 'µ' : '_', '¶' : '_', '·' : '_',
'¸' : '_', '¹' : '_', 'º' : '_', '»' : '_',
'¼' : '_', '½' : '_', '¾' : '_', '¿' : '_',
'À' : 'a', 'Á' : 'a', 'Â' : 'a', 'Ã' : 'a',
'Ä' : 'a', 'Å' : 'a', 'Æ' : 'ae', 'Ç' : 'c',
'È' : 'e', 'É' : 'e', 'Ê' : 'e', 'Ë' : 'e',
'Ì' : 'i', 'Í' : 'i', 'Î' : 'i', 'Ï' : 'i',
'Ð' : '_', 'Ñ' : 'n', 'Ò' : 'o', 'Ó' : 'o',
'Ô' : 'o', 'Õ' : 'o', 'Ö' : 'o', '×' : '_',
'Ø' : '_', 'Ù' : 'u', 'Ú' : 'u', 'Û' : 'u',
'Ü' : 'u', 'Ý' : 'y', 'Þ' : '_', 'ß' : '_',
'à' : 'a', 'á' : 'a', 'â' : 'a', 'ã' : 'a',
'ä' : 'a', 'å' : 'a', 'æ' : 'ae', 'ç' : 'c',
'è' : 'e', 'é' : 'e', 'ê' : 'e', 'ë' : 'e',
'ì' : 'i', 'í' : 'i', 'î' : 'i', 'ï' : 'i',
'ð' : '_', 'ñ' : 'n', 'ò' : 'o', 'ó' : 'o',
'ô' : 'o', 'õ' : 'o', 'ö' : 'o', '÷' : '_',
'ø' : '_', 'ù' : 'u', 'ú' : 'u', 'û' : 'u',
'ü' : 'u', 'ý' : 'y', 'þ' : '_', 'ÿ' : 'y',
'Y' : 'y'}
for letra in nome:
id = id + dicionario[letra]
return id
Não se preocupe, criamos quase toda a tabela ascii para você... É só copiar :) 4.2. Editar as propriedadesSubstitua o conteúdo de PrecosItem_addForm por:
<html>
<head><title>Adicionar PrecosItem</title></head>
<body bgcolor="#FFFFFF" link="#000099" vlink="#555555">
<h2>Adicionar PrecosItem</h2>
<form action="PrecosItem_add">
<table>
<tr><th>Item</th>
<td><input type="text" name="nome" /></td>
</tr>
<tr><th>Preço</th>
<td><input type="text" name="preco" /></td>
</tr>
<tr><td colspan="2" align="center">
<input type="submit" value=" Adicionar " />
</td></tr>
</table>
</form>
</body>
</html>
Substitua o conteúdo de PrecosItem_add por:
<html>
<head><title>Adicionar PrecosItem</title></head>
<body bgcolor="#FFFFFF" link="#000099" vlink="#555555">
<dtml-call "REQUEST.set('id',ide(nome))">
<dtml-with "PrecosItem.createInObjectManager(REQUEST['id'], REQUEST)">
<dtml-call "propertysheets.PrecosItem.manage_editProperties(REQUEST)">
</dtml-with>
<dtml-if DestinationURL>
<dtml-call "RESPONSE.redirect(DestinationURL+'/manage_workspace')">
<dtml-else>
<dtml-call "RESPONSE.redirect(URL2+'/manage_workspace')">
</dtml-if>
</body>
</html>
Acabamos de possibilitar a criação de itens com seus respectivos nome e
preço. Como precisamos de um Id, o criamos partir do nome, alterando os
caracteres especiais. Isso foi feito na linha
4.3. Catalogar automaticamente os itensInsira , entre as tagsdtml-with "PrecosItem.createInObjectManager(REQUEST['id'], REQUEST)" e /dtml-with o seguinte código:
<dtml-call "manage_editCataloger('catalogoItens')">
<dtml-call reindex_object>
5. Permitir edição dos objetosComo criamos propriedades personalizadas tanto para PrecosFolder quanto para PrecosItem, teremos que alterar também as abas do Zope que aparecem quando clicamos numa instância do objeto. No caso de PrecosItem, teremos que criar um formulário e um método capazes de recatalogar a instância editada.5.1. Determinar quais abas do Zope serão exibidasAntes de definir as abas, vamos definir um método padrão de exibição (e que será utilizado como a aba 'View'). Dentro da classe PrecosFolder, crie um método com Id "index_html": <dtml-var standard_html_header> <dtml-var MostrarTabela> <dtml-var standard_html_footer> O método MostrarTabela será criado posteriormente. Optamos por mantê-lo como um método separado pois poderá ser reutilizado em outros casos. Dentro da classe PrecosFolder, clique na aba 'Views'. Por padrão haverá apenas "Contents". Adicionaremos as seguintes:
Poderemos assim administrar todas as características de PrecosFolder, incluindo permissões de acesso e capacidade de desfazer mudanças. 5.2. Recatalogar o item após ediçãoPara PrecosItem, entretanto, o formulário padrão 'propertysheets/PrecosItem/manage' não é suficiente, já que não reindexa o item no zcatalog. Dentro da classe PrecosItem, adicione um método com Id "PrecosItemEditForm":
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<form action="PrecosItemEdit">
<table>
<tr><th>Item</th>
<td><input type="text" name="nome" value="&dtml-nome;" /></td>
</tr>
<tr><th>Preço</th>
<td><input type="text" name="preco" value="&dtml-preco;" /></td>
</tr>
<tr><td colspan="2" align="center">
<input type="submit" value=" Editar " />
</td></tr>
</table>
</form>
<dtml-var manage_page_footer>
Adicione, com Id "PrecosItemEdit", o método que processará o formulário acima:
<html>
<head><title>Edit PrecosItem</title></head>
<body bgcolor="#FFFFFF" link="#000099" vlink="#555555">
<dtml-call "propertysheets.PrecosItem.manage_editProperties(REQUEST)">
<dtml-call "manage_editCataloger('catalogoItens')">
<dtml-call reindex_object>
<dtml-if DestinationURL>
<dtml-call "RESPONSE.redirect(DestinationURL+'/manage_workspace')">
<dtml-else>
<dtml-call "RESPONSE.redirect(URL2+'/manage_workspace')">
</dtml-if>
</body>
</html>
Dentro da classe PrecosItem, clique na aba 'Views'. Por padrão haverá "Undo", "Ownership" e "Security". Apague se desejar. Adicionaremos apenas:
6. Criar visualizações padrão para os objetosFalta criar o método MostrarTabela, dentro da classe PrecosFolder, e ensinar como criar um formulário de busca. Dentro da classe PrecosFolder, crie um método com Id "MostrarTabela" (modifique as cores segundo sua conveniência): <table width="100%" border="0" align="center" cellspacing="0"> <tr><td align="center" bgcolor="#5f633d" colspan="2"> <b><dtml-var title_or_id></b> </td></tr> <dtml-in catalogoItens sort=id> <dtml-if sequence-odd> <tr bgcolor="#ffffff"> <dtml-else> <tr> </dtml-if> <td align="left" valign="top"><dtml-var nome></td> <td align="right" valign="top"><dtml-var preco></td> </tr> </dtml-in> </table> Como dissemos anteriormente, esse método MostrarTabela poderia ser reutilizado. Ele será útil para mostrar os resultados de uma busca. Dentro da classe PrecosFolder, crie um método com Id "searchResults":
<dtml-call "REQUEST.set('nome', chaveBusca(txtbusca))">
<dtml-var MostrarTabela>
O método searchResults utiliza um pequeno script python com Id "chaveBusca" cujo objetivo é acrescentar "*s" às palavras da busca. Crie-o, com "entrada" como 'Parameter':
from string import split, rstrip
chaves=split(entrada)
chave=''
for i in chaves:
chave=chave+i+'* '
rstrip(chave)
return chave
7. TestarAgora crie instâncias de PrecosFolder. Note que cada uma delas já contém um zcatalog. Crie instâncias de PrecosItems para suas PrecosFolders. Note que elas são catalogadas automaticamente. Altere os preços de seus itens e veja o que acontece com o catálogo. Caso você deseje ter uma página exibindo todas as listas de preço, coloque os seguintes documentos e métodos no mesmo diretório de suas PrecosFolders: index_html
<dtml-var standard_html_header>
<h1>Listas de preços</h1>
<table width="100%" border="0" align="center">
<tr>
<td align="center" bgcolor="#5f633d" class="cab" colspan="2">Listas</td>
</tr>
<dtml-with expr="PARENTS[0]">
<dtml-in expr="objectValues('PrecosFolder')" sort=title>
<tr><td>
<a href="&dtml-absolute_url;"><dtml-var title_or_id></a>
</td></tr>
</dtml-in>
</dtml-with>
<tr><td align="right"><a href="manage">[editar]</a></td></tr>
<tr><td align="center">
<form action="Results" method="get">
<b>Item:</b>
<input name="txtbusca" width="30" value="" />
<input type="SUBMIT" name="SUBMIT" value="Procurar" />
</form>
</td></tr>
</table>
<dtml-var standard_html_footer>
Results
<dtml-var standard_html_header>
<dtml-comment>
Faz a busca em todos os itens do tipo
PrecosFolder contíguos.
</dtml-comment>
<dtml-in "objectValues('PrecosFolder')" sort=title>
<dtml-var searchResults>
<br /> <br />
</dtml-in "objectValues('PrecosFolder')">
<dtml-var standard_html_footer>
Mais...Por questões estéticas, seria interessante acrescentar ícones aos
objetos que criamos (aqui usamos
Futuramente alteraremos as permissões de segurança de PrecosFolder automaticamente para que usuários do tipo owner possam adicionar, editar e excluir itens. |