You are not logged in Log in Join
You are here: Home » Members » dedalu » Construir uma lista de itens e preços (zclass e zcatalog)

Log in
Name

Password

 

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ções

Assumimos 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.

Metas

Ao 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 zclasses PrecosFolder e, dentro dela, PrecosItem
  2. Adicionar propriedades personalizadas
  3. Modificar os scripts de construção de PrecosFolder para:
    • editar as propriedades e
    • criar um zcatalog
  4. Modificar os scripts de construção de PrecosItem para:
    • criar um Id automaticamente,
    • editar as propriedades e
    • catalogar automaticamente os itens
  5. Permitir edição dos objetos:
    • determinar quais abas do Zope serão exibidas e
    • criar um script para recatalogar o citem após edição
  6. Criar visualizações padrão para os objetos
  7. Testar
  8. Mais...

1. Criar as classes

Em '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:

Estrutura

2. Adicionar propriedades personalizadas

Dentro 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:

NameTypeValue
"Title"string 

Dentro da classe PrecosItem, de forma semelhante à ilustrada acima, adicione o seguinte à folha de propriedades PrecosItem da classe PrecosItem:

NameTypeValue
"nome"string 
"preco"string 

3. Modificar os scripts de construção de PrecosFolder

Tudo 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 propriedades

Substitua 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:
dtml-with "PrecosFolder.createInObjectManager(REQUEST['id'], REQUEST)"
cria o objeto e o seleciona como escopo das variáveis para que
dtml-call "propertysheets.PrecosFolder.manage_editProperties(REQUEST)"
modifique a folha de propriedades PrecosFolder com base nas variáveis passadas pelo objeto REQUEST.

3.2. Criando um zcatalog

Adicione o seguinte código a PrecosFolder_add no primeiro dtml-with, para que o zcatalog seja criado dentro do PrecosFolder (e não no diretório corrente):

<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 PrecosItem

PrecosItem 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 automaticamente

Vamos 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 propriedades

Substitua 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 dtml-call "REQUEST.set('id',ide(nome))".

4.3. Catalogar automaticamente os itens

Insira , entre as tags dtml-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 objetos

Como 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 exibidas

Antes 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:

NameMethod
Propertiespropertysheets/PrecosFolder/manage
Viewindex_html
Securitymanage_access
Undomanage_undo

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ção

Para 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:

NameMethod
EditPrecosItemEditForm

6. Criar visualizações padrão para os objetos

Falta 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. Testar

Agora 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
tipo: DTML Document
conteúdo:

<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
tipo: DTML Method
conteúdo:

<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 icon e icon. Para isso, entre em '/Control_Panel/Products/PrecosFolder', clique na aba 'Basic', clique em 'Browse...' e selecione uma figura em formato gif 16x16 para dar upload. Faça o mesmo para PrecosItem.

Futuramente alteraremos as permissões de segurança de PrecosFolder automaticamente para que usuários do tipo owner possam adicionar, editar e excluir itens.