10.
Modelo de Página Avançado
Um nível acima
No Capítulo "Usando Modelos de Páginas no Zope" você aprendeu o básico sobre Modelos de Páginas. Neste capítulo você aprenderá sobre técnicas avançadas incluindo novos tipos de expressões e macros.
TAL Avançada
Você já aprendeu sobre algumas expressões TAL. Nesta seção nós veremos todas as expressões TAL e suas várias opções. Note, esse material é abordado mais resumidamente no Apêndice C, "Referências a Modelos de Páginas do Zope".
Inserção Avançada de Conteúdo
Você já viu como tal:content e tal:replace funcionam no Capítulo 5, "Usando Modelos de Páginas do Zope". Nesta seção você aprenderá algumas dicas avançadas para a inserção de conteúdo.
Inserindo Estruturas
Normalmente, as expressões tal:replace e tal:content introduzem tags e entidades HTML
no texto que elas inserem, convertendo < para <, por exemplo. Se você realmente quer
inserir o texto sem aspas, você precisa preceder a expressão com a palavra-chave structure.
Por exemplo:
<p replace="structure here/story">
the <b>story</b>
</p>
Essa característica é útil quando você está inserindo um fragmento de HTML ou XML que está armazenado em uma propriedade ou que foi gerado por outro objeto do Zope. Por exemplo, você pode ter novos itens que contenham tags HTML simples como texto em negrito e itálico quando eles são renderizados, e você quer preservar isso quando inseri-los em uma página de "Top News". Neste caso, você deve escrever:
<p tal:repeat="newsItem here/topNews"
tal:content="structure newsItem">
A news item with<code>HTML</code> markup.
</p>
Isso irá inserir os novos itens incluindo suas tags HTML em parágrafos.
Elementos de Imitação
Você pode incluir elementos de páginas que estejam visíveis no modelo mas não no texto gerado usando a variável embutida nothing, como nesse exemplo:
<tr tal:replace="nothing">
<td>10213</td><td>Example Item</td><td>$15.34</td>
</tr>
Isso pode ser útil para preencher partes da página que serão ocupadas com conteúdo dinâmico. Por exemplo, uma tabela que normalmente tem 10 linhas terá apenas uma linha no modelo. Adicionando nove linhas de imitação, o layout do modelo se parecerá mais com o resultado final.
Não é preciso usar sempre tal:replace="nothing" para conseguir conteúdo modelo em seus Modelos de Páginas. Por exemplo, você já viu que normalmente nada dentro de um tal:content ou tal:replace é removido quando o modelo é renderizado. Nesses casos você não tem que fazer nada em especial para se certificar de que o conteúdo modelo foi removido.
Conteúdo Padrão
Você pode deixar o conteúdo de uma tag para adiante usando a expressão default com tal:content ou tal:replace. Por exemplo:
<p tal:content="default">Spam<p>
Isso é interpretado como:
Spam
Mais freqüentemente você irá querer incluir conteúdo padrão seletivamente, ao invés de sempre incluir isso. Por exemplo:
<p tal:content="python:here.getFood() or default">Spam</p>
Nota: expressões Python serão explicadas mais tarde no capítulo. Se o método getFood retornar um valor verdadeiro então seu resultado será inserido no parágrafo, senão é um Spam.
Repetição Avançada da Tag
Você já viu quase tudo que pode ser feito com a expressão tal:repeat no Capítulo 5, "Usando Modelos de Páginas do Zope ". Essa seção abrange algumas características avançadas da expressão tal:repeat.
Variáveis de Repetição
Um tópico que pode apresentar mais explicações é o das variáveis de repetição. Variáveis de repetição fornecem informação sobre a repetição em andamento. Esses atributos estão disponíveis nas variáveis repeat:
- index - repetição de números, começando do zero.
- number - repetição de números, começando do 1.
- even - verdadeiro para repetições even-indexed (0, 2, 4, ...).
- odd - verdadeiro para repetições odd-indexed (1, 3, 5, ...).
- start - verdadeiro para o começo da repetição (index 0).
- end - verdadeiro para a conclusão, ou final, da repetição.
- length - tamanho da seqüência - que será o número total de repetições.
- letter - conta reps com letras lower-case (letras minúsculas): "a" - "z", "aa" - "az", "ba" - "bz", ..., "za" - "zz", "aaa" - "aaz", e assim por diante.
- Letter - versão upper-case (maiúscula) de letter.
Você pode acessar os conteúdos de uma variável de repetição usando expressões path ou expressões Python. Em expressões path, você escreve um path em três partes consistindo no nome repeat, a expressão do nome da variável, e o nome da informação que você quer, por exemplo, repeat/item/start. Em expressões Python, você normalmente usa notação de dicionários para obter a variável de repetição, e após atributos de acesso para obter a informação, por exemplo, 'python:repeat['item'].start'.
Dicas de Repetição
Aqui estão algumas dicas práticas que você pode achar útil. Algumas vezes você quer repetir uma tag, mas não tem uma tag de fechamento. Por exemplo, você pode querer repetir várias tags de parágrafo, mas não há necessidade de fechá-las em outra tag. Você pode fazer isso com a expressão tal:omit-tag:
<div tal:repeat="quote here/getQuotes"
tal:omit-tag="">
<p tal:content="quote">quotation</p>
</div>
A expressão tal:omit-tag será descrita mais tarde neste capítulo.
Mesmo que já tenha sido mencionado antes, é melhor dizer novamente: você pode colocar expressões tal:repeat uma dentro da outra. Cada expressão tal:repeat deve ter uma variável de repetição com nome diferente. Aqui está um exemplo que mostra uma tabela-tempo aritmética:
<table border="1">
<tr tal:repeat="x python:range(1, 13)">
<div tal:repeat="y python:range(1, 13)"
tal:omit-tag="">
<td tal:content="python:%d x %d = %d% (x, y, x*y)">
X x Y = Z
</td>
</div>
</tr>
</table>
Esse exemplo usa expressões Python e a expressão tal:omit-tag, ambas serão tratadas mais tarde neste capítulo.
Se você trabalha muito com a expressão de repetição do DTML dtml-in, você terá paginações inesperadas. Paginação é o processo de dividir uma lista extensa em listas menores. Você usa isso tipicamente para exibir um número menor de itens de uma lista extensa em uma página da web. Pense em como um mecanismo de busca pagina seus resultados. A expressão tal:repeat não suporta paginação, mas o Zope possui uma utilidade de paginação. Veja a seção, "Paginação" mais adiante neste capítulo.
Outra característica útil que não é suportada pela tal:repeat é a classificação. Se você quer classificar uma lista você pode tanto escrever seu próprio script de classificação (que é mais fácil em Python) como usar a função utilitária sequence.sort. Aqui está um exemplo de como classificar uma lista de objetos por título e após por data de modificação:
<table tal:define="objects here/objectValues;
sort_on python:((title,nocase,asc),
(bobobase_modification_time,cmp,desc));
sorted_objects python:sequence.sort(objects, sort_on)">
<tr tal:repeat="item sorted_objects">
<td tal:content="item/title">title</td>
<td tal:content="item/bobobase_modification_time">
modification date</td>
</tr>
</table>
Esse exemplo tenta fazer coisas claramente ao definir os argumentos da classificação fora da função sort. Você chama a função sequence.sort pegando uma seqüência e uma descrição de como classificá-los. Neste exemplo a descrição de como classificar a seqüência é definida na variável sort_on. Veja o Apêndice B, "Referência API" para mais informação sobre a poderosa função sequence.sort.
Controle Avançado do Atributo
Você já conhece a expressão tal:attributes. Você pode usá-la dinamicamente substituindo atributos da tag, por exemplo, o atributo href em um elemento a. Você pode substituir mais do que um atributo em uma tag ao separar atributos com ponto e vírgula:
<a href="link"
tal:attributes="href here/getLink;
class here/getClass">link</a>
Você também pode definir atributos com namespaces XML. Por exemplo:
<Description
dc:Creator="creator name"
tal:attributes="dc:Creator here/owner/getUserName">
Description</Description>
Simplesmente coloque o prefixo namespace XML antes do atributo name e você pode criar atributos com namespaces XML.
Definindo Variáveis
Você pode definir suas próprias variáveis usando o atributo tal:define. Existem várias razões para que você queira fazer isso. Uma razão é evitar ter que escrever longas expressões repetidamente em um modelo. Outro é evitar ter que chamar métodos muito extensos repetidamente. Você pode definir uma variável uma vez e então usá-la várias vezes em um modelo. Por exemplo, aqui está uma lista que define uma variável, testa ela e depois gera uma repetição sobre ela:
<ul tal:define="items container/objectIds"
tal:condition="items">
<li tal:repeat="item items">
<p tal:content="item">id</p>
</li>
</ul>
A expressão tal:define cria a variável items que você pode usar em qualquer lugar na tag ul. Note também como você pode ter duas expressões TAL na mesma tag ul. Veja depois, neste mesmo capítulo, a seção "Interações Entre Expressões TAL" para mais informações sobre como usar mais de uma expressão em uma tag. Neste caso a primeira expressão usa a variável items e a segunda usa items em uma condição para ver se ela é ou não é falsa (neste caso, uma seqüência vazia) ou verdadeira. Se a variável items for falsa, então a tag ul não é mostrada.
Agora, suponha que ao invés de simplesmente remover a lista quando não houver itens, você queira mostrar uma mensagem. Para fazer isso, coloque o seguinte antes da lista:
<h4 tal:condition="not:container/objectIds">There
Are No Items</h4>
A expressão not:container/objectIds é verdadeira quando container/objectIds é falsa, e vice versa. Veja a seção, "Expressões Not" mais adiante neste capítulo para mais informação.
Você não pode usar suas variáveis items aqui, pois elas não foram definidas ainda. Se você mover a definição de items para a tag h4, você não poderá mais usá-la na tag ul porque ela se tornou uma variável local da tag h4. Você pode colocar a definição em algumas tags que finalizam a h4 e a ul, mas existe uma solução mais simples. Ao colocar a palavra-chave global na frente da variável name, você pode fazer a definição durar da tag h4 até o final do modelo:
<h4 tal:define="global items container/objectIds"
tal:condition="not:items">There Are No Items</h4>
Você pode definir mais do que uma variável usando tal:define ao separá-las com ponto e vírgula. Por exemplo:
<p tal:define="ids container/objectIds;
title container/title">
Você pode definir quantas variáveis quiser. Cada variável pode ter seu próprio âmbito global ou local. Você também pode fazer referências a variáveis definidas anteriormente em definições posteriores. Por exemplo:
<p tal:define="title template/title;
tlen python:len(title);">
Com uso ponderado de tal:define você pode melhorar a eficiência e a capacidade de leitura de seus modelos.
Omitindo Tags
Você pode remover tags com a expressão tal:omit-tag. Você raramente precisará usar essa expressão TAL, mas ocasionalmente é útil. O atributo omit-tag remove uma tag, mas não afeta seu conteúdo. Por exemplo:
<b tal:omit-tag=""><i>this</i> stays</b>
É renderizado:
<i>this</i> stays
Nesse nível de uso, tal:omit-tag opera quase como tal:replace="default". No entanto, tal:omit-tag é mais útil quando usada em combinação com outra expressão TAL como tal:repeat. Por exemplo, eis uma forma de criar 10 tags de parágrafo usando tal:repeat:
<span tal:repeat="n python:range(10)"
tal:omit-tag="">
<p tal:content="n">1</p>
</span>
Isso irá gerar 10 tags de parágrafo, porém, a tag span não aparecerá na saída.
O atributo tal:omit-tag retira uma expressão, contudo normalmente você usará somente uma expressão vazia. Se a expressão é verdadeira ou se não há expressão então a expressão tag é removida. Se a expressão é falsa, então a tag não é omitida. Isso permite que você remova as tags seletivamente dependendo da dinâmica da circunstância.
Tratamento de Erro
Se um erro ocorre no seu modelo de página, você pode pegar esse erro e mostrar uma mensagem de erro muito útil ao seu usuário. Por exemplo, suponha que seu modelo define uma variável usando uma estrutura de dados:
...
<span tal:define="global prefs request/form/prefs"
tal:omit-tag="" />
...
Se o Zope encontrar um problema, como não achar a variável prefs na estrutura de dados, a página inteira trancará e você terá no seu lugar uma página de erro. Felizmente, você pode evitar esse tipo de coisa com tratamento limitado de erro usando a expressão tal:on-error:
...
<span tal:define="global prefs here/scriptToGetPreferences"
tal:omit-tag=""
tal:on-error="string:An error occurred">
...
Quando um erro é detectado ao carregar o modelo, o Zope procura por uma expressão tal:on-error para tratar do erro. Primeiro ele procura na tag corrente, depois na tag de fechamento, e assim por diante até chegar na tag top-level (nível superior). Quando ele encontra um tratador de erro, ele substitui os conteúdos da tag com as expressões de tratamento de erro. Nesse caso, a tag span irá conter uma mensagem de erro.
Tipicamente você definirá um tratador de erros em uma tag que finaliza um elemento lógico da página, uma tabela, por exemplo. Se um erro surgir inserindo a tabela, então o tratador de erros pode simplesmente omitir a tabela da página, ou também repô-la com uma mensagem de erro de alguma classificação.
Para um tratamento de erros mais flexível você pode chamar um script. Por exemplo:
<div tal:on-error="structure here/handleError">
...
</div>
Qualquer erro que ocorrer dentro do div chamará o script handleError. Note que a opção structure permite que o script dê retornos em HTML. Seu script de tratamento de erros pode examinar o erro e tomar várias atitudes dependendo do erro. Seu script tem acesso ao erro através da variável error no namespace. Por exemplo:
## Script (Python) "handleError"
##bind namespace=_
##
error=_['error']
if error.type==ZeroDivisionError:
return "<p>Can't divide by zero.</p>"
else
return """<p>An error occurred.</p>
<p>Error type: %s</p>
<p>Error value: %s</p>""" % (error.type,
error.value)
Seu script de tratamento de erro pode tomar todo tipo de atitude, por exemplo, ele pode logar o erro ao mandar um e-mail.
A expressão tal:on-error não foi feita para o propósito geral de tratamento de exceções. Por exemplo, você não deve validar dados de entrada no formulário nele. Você deve usar um script para isso, já que os scripts permitem que você faça um poderoso tratamento de exceções. A expressão tal:on-error é para lidar com problemas incomuns que podem ocorrer na renderização de modelos.
Interações Entre Expressões TAL
Quando há apenas uma expressão TAL por elemento, a ordem na qual elas são executadas é simples. Começando com o elemento da raiz, cada expressão do elemento é executada, depois cada um de seus elementos-filhos é visitado, em ordem, e suas expressões são executadas, e assim por diante.
Contudo, é possível que exista mais do que uma expressão TAL no mesmo elemento. Qualquer combinação de expressões pode aparecer no mesmo elemento, menos a combinação em que a expressão tal:content e tal:replace aparecem juntas.
Quando um elemento tem várias expressões, eles são executados nesta ordem:
- define
- condition
- repeat
- content or replace
- attributes
- omit-tag
A expressão tal:on-error não aparece na lista, já que ela é chamada apenas quando ocorre um erro.
A razão por trás desta ordem é que freqüentemente você pode querer definir variáveis para usar em outras expressões, assim a definição vem primeiro. A próxima coisa a fazer é decidir se esse elemento será incluído no todo, a condição vem primeiro; mas se a condição depender das variáveis que você define, ela vem depois da definição. É muito importante ser capaz de repor várias partes de um elemento com diferentes valores a cada interação de uma repetição, assim a repetição vem antes do content, replace e attributes. Content e replace não podem ser usados no mesmo elemento ao mesmo tempo já que eles ocupam o mesmo lugar. Omit-tag vem por último, pois é provável que nenhuma outra expressão dependa dela e porque ela deve vir depois de define e repeat.
Aqui está um exemplo de tag que inclui várias expressões TAL:
<p tal:define="x /root/a/long/path/x | nothing"
tal:condition="x"
tal:content="x/txt"
tal:attributes="class x/class">Ex Text</p>
Veja como a expressão tal:define é executada primeiro e como as outras expressões dependem de seus resultados.
Existem três regras que você deve seguir quando combinar expressões TAL nos elementos:
- Apenas uma expressão de cada tipo pode ser usada em uma tag. Já que HTML não permite vários atributos com o mesmo nome. Por exemplo, você não pode ter dois tal:define na mesma tag.
- tal:content e tal:replace não podem ser usados na mesma tag pois suas funções conflitam.
- A ordem na qual você escreve atributos TAL em uma tag não afeta a ordem na qual eles serão executados. Não importa como você combina as expressões TAL em uma tag, elas sempre são executadas na ordem descrita anteriormente.
Se você quiser passar por cima da ordem das expressões TAL, então você deve fazer isso colocando o elemento dentro de um outro elemento, possivelmente div ou span, e colocar algumas das expressões neste novo elemento. Por exemplo, suponha que você quer dar um loop sobre uma série de itens e deixar alguns de fora. Aqui está uma tentativa de escrever um modelo que dá loops sobre os números de zero a nove e pula três:
<!-- broken template -->
<ul>
<li tal:repeat="n python:range(10)"
tal:condition="python:n != 3"
tal:content="n">
1
</li>
</ul>
Esse modelo não funciona porque a condição é testada antes do repeat ser executado. O resultado é que a variável n só é definida depois de ser testada. Aqui está um jeito de contornar este problema:
<ul>
<div tal:repeat="n python:range(10)"
tal:omit-tag="">
<li tal:condition="python:n != 3"
tal:content="n">
1
</li>
</div>
</ul>
Esse modelo resolve o problema definindo a variável n em uma tag de fechamento div. Note que a tag div não aparecerá na saída devido a sua expressão tal:omit-tag. Isso pode não ter um aspecto muito bom, mas funciona. Talvez as versões futuras dos Modelos de Páginas possam resolver esse problema de uma maneira agradável.
Processamento de Formulário
Você pode processar formulários em DTML usando um modelo comum chamado "form/action pair" ("par formulário/ação"). Um form/action pair consiste de dois métodos DTML ou documentos: um que contém um formulário que lê os dados de entrada do usuário, e um que contêm a ação de pegar esses dados de entrada e retornar ao usuário uma resposta. O formulário chama a ação. Veja o Capítulo 4, "Conteúdo Dinâmico com DTML" para mais informações sobre o modelo form/action.
Os Modelos de Páginas do Zope não trabalham particularmente bem com o modelo form/action já que eles assumem esse processamento de entrada e apresentam respostas que são tratadas pelo mesmo objeto (a ação). Ao invés de usar o modelo form/action você deve usar o modelo form/action/response (formulário/ação/resposta) nos Modelos de Páginas. O formulário e a resposta devem ser Modelos de Páginas e a ação deve ser um script. O modelo do formulário apanha a entrada e chama o script de ação. O script de ação deve processar a entrada e retornar um modelo de resposta. Esse modelo é mais flexível do que o modelo form/action já que ele permite ao script retornar qualquer número dentre diferentes objetos de resposta.
Por exemplo, aqui está uma parte de um modelo de formulário:
...
<form action="action">
<input type="text" name="name">
<input type="text" name="age:int">
<input type="submit">
</form>
...
Esse formulário pode ser processado por esse script:
## Script (Python) "action"
##parameters=name, age
##
container.addPerson(name, age)
return container.responseTemplate()
Esse script chama um método para processar as entradas e retorna outro modelo depois, a resposta. Você pode carregar um Modelo de Página do Python chamando ele. O modelo de resposta tipicamente contém uma confirmação de que o formulário foi processado corretamente. O script de ação pode fazer todo tipo de coisas. Ele pode validar as entradas, tratar erros, mandar e-mail, e muito mais. Aqui está um esboço de como validar as entradas com um script:
## Script (Python) "action"
##
if not context.validateData(request):
# if there's a problem return the form page template
# along with an error message
return context.formTemplate(error_message=Invalid data)# otherwise return the thanks page
return context.responseTemplate()
Esse script dá validade ao formulário de entrada e retorna o modelo de formulário com uma mensagem de erro se houver um problema. Você pode passar informação extra de Modelos de Páginas com argumentos de palavras-chave. Os argumentos de palavras-chave estão disponíveis para o modelo através da variável embutida options. Assim o modelo de formulário nesse exemplo deve incluir uma seção como essa:
A mensagem de erro vai aqui.
Esse exemplo mostra como você pode exibir uma mensagem de erro que é passada ao modelo por meio de argumentos de palavras-chave.
Dependendo da sua aplicação você pode escolher redirecionar o usuário para um Modelo de Página de resposta ao invés de dar um retorno a ele diretamente. Isso resulta em duas vezes mais atividade na rede de trabalho, mas pode ser útil porque muda a URL exibida no browser do usuário para a URL do Modelo de Página, melhor do que o script de ação. Se você insistir em fazer um trabalho de baixa qualidade, você pode criar sempre a versão mais fraca do modelo form-action usando Modelos de Páginas. Você deve fazer isso apenas quando você não se importa com o tratamento de erro e quando a resposta será sempre a mesma, não importa o que o usuário submeter. Já que Modelos de Páginas não tem um equivalente para a dtml-call, você pode usar um dos vários números de cortes para chamar um método de processamento de entrada sem inserir seus resultados. Por exemplo:
<span tal:define="unused here/processInputs"
tal:omit-tag=""/>
Este teste chama o método processInputs e atribui o resultado para a variável unused.
Expressões
Você já encontrou expressões de Modelos de Página. Expressões adquirirem valores para expressões modelo. Por exemplo, expressões path descrevem objetos ao dá-los endereços, tais como request/form/age, ou user/getUserName. Nesta seção você aprenderá sobre todos os diferentes tipos de expressões e variáveis.
Variáveis Embutidas
Variáveis são nomes que você pode usar em expressões. Você já viu alguns exemplos de variáveis embutidas, como template, user, repeat, e request. Aqui está uma lista completa de outras variáveis embutidas e seu uso:
nothing
Um valor falso, similar a uma string em branco, você pode usar em tal:replace ou tal:content para apagar uma tag ou seu conteúdo. Se você definir um atributo para nothing, o atributo é removido da tag (ou não é inserido), diferente do que acontece com uma string em branco.
default
Um valor especial que não muda nada quando usado na tal:replace, tal:content, ou tal:attributes. Ele deixa o texto do modelo no lugar.
options
Os argumentos de palavras-chave, if any, que eram passados para o modelo. Nota: options está disponível apenas quando um modelo é chamado do Python. Quando um modelo é carregado da web, nenhuma opção é apresentada.
attrs
Um dicionário de atributos da tag em uso no modelo. As chaves são os nomes de atributos e os valores são valores originais dos atributos no modelo. Essa variável raramente é necessária.
root
A raiz do objeto Zope. Use isso para obter objetos Zope de locações fixadas, não importa onde seu modelo está situado ou chamado.
here
O objeto no qual o modelo está sendo chamado. Essa variável é tão freqüente quanto a variável container, mas pode ser diferente se você está usando aquisição. Use ela para obter objetos Zope que você espera encontrar em lugares diferentes dependendo de como o modelo for chamado. A variável here é similar à variável context em scripts Python-based.
container
O contêiner (usualmente uma Pasta) no qual os modelos são guardados. Use isso para obter objetos Zope de locações relativas ao home permantente do modelo. A variável container e here se referem ao mesmo objeto quando um modelo é chamado de sua locação normal. Contudo, quando um modelo é aplicado a outro objeto (por exemplo, um Método ZSQL) container e here não farão referência ao mesmo objeto.
modules
Coleção disponível de módulos Python para modelos. Veja a seção sobre como escrever expressões Python.
Você encontrará exemplos de como usar essas variáveis ao longo desse capítulo.
Expressões String
Expressões String permitem que você combine facilmente expressões path com texto. Todo o texto depois da guia string: é tomada e procurada por expressões path. Cada expressão path deve ser precedida pelo sinal de dólar ($). Aqui estão alguns exemplos:
"string:Just text. There's no path here."
"string:copyright $year, by me."
Se a expressão path tiver mais de uma parte, ou precisar ser separada do texto que a segue, ela deve ser envolvida por chaves ({}). Por exemplo:
"string:Three ${vegetable}s, please."
"string:Your name is ${user/getUserName}!"
Veja como no exemplo acima, você precisa envolver a path vegetable com chaves para que o Zope não confunda com vegetables.
Já que o texto está dentro de um valor atributo, você pode incluir somente
uma quota dupla ao usar a sintaxe da entidade ". Já que o sinal de dólar
é usado para assinalar expressões path, um sinal de dólar literal deve ser escrito
como dois sinais de dólar ($$). Por exemplo:
"string:Please pay $$$dollars_owed"
"string:She said, "Hello world.""
Algumas operações complexas de formatação de strings (tais como procura e substituição ou troca de letras maiúsculas) não podem ser feitas facilmente com expressões string. Para esses casos, você deve usar expressões Python ou Scripts.
Expressões Path
Expressões path são usadas em objetos com um endereço que se parece com um endereço de URL. Um path descreve um traversal de objeto a objeto. Todos os paths começam com um objeto conhecido (assim como uma variável embutida, uma variável de repetição ou uma variável definida pelo usuário) e partem daí para o objeto desejado. Aqui estão alguns exemplos de expressões path:
template/title
container/files/objectValues
user/getUserName
container/master.html/macros/header
request/form/address
root/standard_look_and_feel.html
Com expressões path você pode traverse de um objeto para seus sub-objetos incluindo propriedades e métodos. Você também pode usar aquisição em expressões path. Veja a seção "Chamando Scripts da Web" no Capítulo 8, "Scripts Avançados do Zope" para mais informações sobre aquisição e path traversal.
O Zope restringe traversal objetos em expressões path do mesmo jeito que restringe acesso a objetos via URLs. Você deve ter permissões adequadas para acessar um objeto para se referir a ele com uma expressão path. Veja o Capítulo 6, "Usuários e Segurança" para mais informações sobre controle de acesso a objetos.
Paths Alternados
O endereço template/title tem garantia de existir a cada vez que o modelo é usado, mesmo sendo uma string em branco. Alguns paths, como request/form/x, podem não existir durante o carregamento do modelo. Isso normalmente causa erros quando o Zope avalia a expressão path.
Quando um endereço não existe, você pode ter um path fall-back ou valores que você gostaria de usar no seu lugar. Por exemplo, se request/form/x não existir você deve usar no seu lugar here/x. Você pode fazer isso ao listar os endereços em ordem de preferência, separados pelo caractere barra vertical (|):
<h4 tal:content="request/form/x | here/x">Header</h4>
As variáveis nothing e default são muito úteis em uma lista de alternativas, como o endereço visto anteriormente. Por exemplo, default diz a tal:content para deixar o conteúdo modelo. Expressões TAL diferentes interpretam default e nothing diferentemente. Veja o Apêndice C, "Referências a Modelos de Páginas do Zope" para mais informação.
Você pode usar também uma expressão não-path como a última parte em uma expressão de path-alternado. Por exemplo:
<p tal:content="request/form/age|python:18">age</p>
Nesse exemplo, se o endereço request/form/age não existe, então o valor é o número 18. Esse formulário permite que você especifique valores padrão para usar que não podem ser expressados como paths. Veja, você pode usar apenas uma expressão não-path como última alternativa.
Você pode testar também a existência de um endereço diretamente com o prefixo tipo expressão exists. Veja a seção "Expressões Exist" abaixo para mais informações sobre expressões exists.
Expressões Not
As expressões Not deixam você negar o valor de outras expressões. Por exemplo:
<p tal:condition="not:here/objectIds">
There are no contained objects.
</p>
As Expressões Not retornam verdadeiro quando a expressão na qual elas estão sendo usadas é falsa, e vice versa. Em Zope, variáveis non-existent, zero, strings vazias, seqüências vazias, nothing, and None são consideradas falso, enquanto que todo o resto é verdadeiro.
Não há muita razão para usar expressões not com expressões Python já que, em Python, você pode usar a palavra-chave not no seu lugar.
Expressões Nocall
Uma expressão path comum tenta carregar o objeto que ela busca. Isso significa que se o objeto é uma função, um Script, um Método, ou algum outro tipo de coisa executável, então a expressão irá avaliar para o resultado de chamar o objeto. Geralmente é isso que você quer, mas nem sempre. Por exemplo, se você quer por um Documento DTML dentro de uma variável para que você possa aplicar-se de suas propriedades, você não pode usar uma expressão path normal porque ela irá carregar o Documento como uma string.
Se você colocar a expressão type prefix nocall: na frente de um path, isso evita a interpretação e simplesmente lhe fornece o objeto. Por exemplo:
<span tal:define="doc nocall:here/aDoc"
tal:content="string:${doc/getId}: ${doc/title}">
Id: Title</span>
Esse tipo de expressão também é importante quando você quer definir uma variável para envolver uma função ou uma classe de um modulo, para usar em uma expressão Python.
As expressões nocall podem ser usadas também em funções, e não só em objetos:
<p tal:define="join nocall:modules/string/join">
Essa expressão define a variável join como uma função (string.join), e não só como o resultado de chamar uma função.
Expressões Exists
Uma expressão exists é verdadeira se seu endereço existe, senão é falsa. Por exemplo aqui está um jeito de mostrar uma mensagem de erro apenas se ela passar pelo que é solicitado:
<h4 tal:define="err request/form/errmsg | nothing"
tal:condition="err"
tal:content="err">Error</h4>
Você pode fazer a mesma coisa mais facilmente com uma expressão exists:
<h4 tal:condition="exists:request/form/errmsg"
tal:content="request/form/errmsg">Error!</h4>
Você pode combinar expressões exists com expressões not, por exemplo:
<p tal:condition="not:exists:request/form/number">Por favor digite um número entre 0 e 5</p>
Note que neste exemplo você não pode usar a expressão, "not:request/form/number", já que essa expressão será verdadeira se a variável number existir e for zero.
Expressões Python
A lingugem de programação Python é simples e expressiva. Se você nunca trbalhou com ela antes, você deve ler um dos excelentes tutoriais ou introduções disponíveis no website da Python.
Uma expressão Modelo de Página Python pode conter qualquer coisa que a linguagem Python considerar uma expressão. Você não pode usar expressões como if e while. Em adição, o Zope impõem algumas restrições de segurança para que você continue acessando informação protegida, trocando dados seguros, e criando problemas como loops infinitos. Veja o Capítulo 8, "Scripts Avançados em Zope" para mais informações sobre restrições de segurança do Python.
Comparações
Um lugar onde expressões Python são praticamente necessárias é na expressão tal:condition. Geralmente você quer comparar duas strings ou números, e não há nenhuma outra maneira de fazer isso sem expressões Python. Você pode usar os operadores de comparação < (menor que), > (maior que), == (igual a), e != (diferente de). Você também pode usar os operadores booleanos and, not e or. Por exemplo:
<p tal:repeat="widget widgets">
<span tal:condition="python:widget.type ==gear>
Gear #<span tal:replace="repeat/widget/number>1</span>:
<span tal:replace="widget/name">Name</span>
</span>
</p>
Esse exemplo dá um loop sobre uma coleção de objetos, testando cada atributo do objeto type.
Algumas vezes você quer escolher valores diferentes dentro de uma única expressão baseada em uma ou mais condições. Você pode fazer isso com a função test:
Você <span tal:define="name user/getUserName"
tal:replace="python:test(name==Anonymous User,
need to log in, default)">
está logado como
<span tal:replace="name">Nome</span>
</span>
A função test trabalha como uma expressão if/then/else (se/então/senão). Veja Apêndice A, "Referência DTML" para mais informação sobre a função test. Aqui está outro exemplo de como você pode usar a função test:
<tr tal:define="oddrow repeat/item/odd"
tal:attributes="class python:test(oddrow,oddclass,
evenclass)">
Sem a função test você teria que escrever dois elementos tr cada um com uma condição diferente, um para even rows, e outro para odd rows.
Usando outros Tipos de Expressões
Você pode usar outros tipos de expressões dentro de uma expressão Python. Cada tipo de expressão tem uma função correspondente com o mesmo nome, incluindo: path(), string(), exists(), e nocall(). Isso permite que você escreva expressões como:
"python:path(here/%s/thing% foldername)"
"python:path(string(here/$foldername/thing))"
"python:path(request/form/x) or default"
O exemplo final tem um significado um pouco diferente da expressão path, "request/form/x | default", já que ele usará o texto default se "request/form/x" não existir ou se ele for falso.
Obtendo Objetos do Zope
Muito do poder do Zope envolve vinculação de objetos especializados. Seus Modelos de Páginas podem usar Scripts, Métodos SQL, Catálogos, e custom content objects. Para usar esses objetos você também tem que saber como conseguir acessá-los sem Modelos de Páginas.
As propriedades de objetos usualmente são atributos, então você pode obter um título do modelo com a expressão "template.title". A maioria dos objetos Zope suportam aquisição, o que permite que você obtenha atributos de objetos "pais". Isso significa que a expressão Python "here.Control_Panel" irá adquirir o objeto Painel de Controle do Folder raiz. Métodos de objetos são atributos, como em "here.objectIds" e "request.set". Objetos contidos em um Folder podem ser acessados como atributos do Folder, mas desde que eles freqüentemente tenham Ids que não sejam identificadores Python válidos, você não pode usar a notação normal. Por exemplo, você não pode usar essa expressão Python:
"python:here.penguin.gif"'.
Você deve escrever:
"python:getattr(here,penguin.gif)"
Já que Python não suporta nomes de atributos com períodos.
Alguns objetos, como request, modules, e Folders do Zope suportam itens de acesso Python, por exemplo:
request['URL']
modules['math']
here['thing']
Quando você usa acesso a itens em um Folder, ele não tenta adquirir o nome, então terá sucesso apenas se realmente houver um objeto que contenha esse Id no Folder.
Como foi mostrado nos capítulos anteriores, expressões path permitem que você ignore detalhes sobre como você obtém de um objeto para o próximo. O Zope tenta acesso ao atributo, depois acesso ao item. Você pode escrever:
"here/images/penguin.gif"
no lugar de:
"python:getattr(here.images,penguin.gif)"
e:
"request/form/x"
no lugar de:
"python:request.form['x']"
Por outro lado, expressões path não permitem que você especifique esses detalhes. Por exemplo, se você tem uma variável formulário nomeada "get", você deve escrever:
"python:request.form['get']"
já que essa expressão path:
"request/form/get"
irá avaliar para o método "get" do dicionário formulário.
Se você preferir você pode usar expressões path dentro de expressões Python usando a função path(), como descrito acima.
Usando Scripts
Objetos Script freqüentemente são usados para encapsular funções lógicas e manipulação complexa de dados. Qualquer vez que você se encontrar escrevendo um monte de expressões TAL que contenham expressões complicadas, você deve considerar que você pode fazer melhor o trabalho usando um Script. Se você tem problemas para entender suas expressões modelo, então é melhor simplificar seu Modelo de Página e usar Scripts para as coisas mais complexas.
Cada Script tem uma lista de parâmetros que ele espera que sejam dados quando ele for chamado. Se esta lista estiver vazia, então você pode usar o Script ao escrever uma expressão path. Ou então, você terá que usar uma expressão Python para suprir o argumento, como esse:
"python:here.myscript(1, 2)"
"python:here.myscript(arg, foo=request.form['x'])"
Se você quer retornar mais do que um item de dados de um Script para um Modelo de Páginas, é uma boa idéia retorna-lo em um dicionário. Dessa forma, você pode definir uma variável para segurar todos os dados, e usar expressões path para referir-se a cada item. Por exemplo, suponha que o script getPerson retorne um dicionário com chaves name e age:
<span tal:define="person here/getPerson"
tal:replace="string:${person/name} is ${person/age}">
Nome tem 30</span> anos de idade.
É claro, é bom para retornar objetos Zope e listas Python também.
Chamando DTML
Diferente dos Scripts, Métodos DTML e Documentos não tem uma lista de parâmetros explicita. Em vez disso, eles esperam que seja passado um cliente, um mapeamento, ou argumentos de palavra-chavas. Eles usam esses parametros para construir um namespace. Veja o Capítulo 7 para mais informação sobre chamadas de DTML.
Quando o Zope publica um objeto DTML através da web, ele passa o contexto do objeto como o cliente, e o REQUEST como o mapeamento. Quando um objeto DTML chama outro, ele passa seu próprio namespace como o mapeamento, e não o cliente.
Se você usa uma expressão path para interpretar um objeto DTML, ela passará um namespace com request, here, e as variáveis do modelo que já estão nele. Isso significa que o objeto DTML será capaz de usar os mesmos nomes como se eles estivessem sendo publicados no mesmo contexto como o modelo, mais a variável nomes definida no modelo.
Módulos Python
A linguagem Python possui um grande número de módulos, que fornecem uma grande variedade de capacidades para programas Python. Cada módulo é uma coleção de funções Python, dados, e classes relacionadas a um único propósito, como cálculos matemáticos ou expressões regulares.
Vários módulos, incluindo "math" e "string", estão disponíveis em expressões Python à revelia. Por exemplo, você pode obter o valor do pi do módulo math escrevendo "python:math.pi". Porém, para acessá-lo de uma expressão path, você terá que usar a variável modules, "modules/math/pi".
O módulo "string" está oculto em expressões Python pela expressão "string" expression tipo função, então você terá que acessa-lo através de variáveis modules. Você pode fazer isso diretamente na expressão na qual você o usa, ou definir uma variável global para ele:
tal:define="global mstring modules/string"
tal:replace="python:mstring.join(slist,:)"
Na prática você raramente terá que fazer isso já que você pode usar métodos string na maior parte do tempo ao invés de ter que depender de funções no módulo string.
Os módulos podem ser agrupados dentro de pacotes, que são simplesmente uma maneira de organizar e nomear módulos relacionados. Por exemplo, Scripts do Zope Python-based são fornecidos por uma coleção de módulos no subpacote "Scripts Python" do Pacote de "Produtos" do Zope. Particularmente, o módulo "padrão" neste pacote fornece um número de funções de formatação úteis que são padrão na tag "var" de DTML. O nome completo desse módulo é "Products.PythonScripts.standard", assim você pode obter acesso a ele usando as expressões abaixo:
tal:define="global pps modules/Products/PythonScripts/standard"
tal:define="global pps python:modules['Products.PythonScripts.standard']"
A maior parte dos módulos Python não podem ser acessados de Modelos de Páginas, DTML, ou Scripts a não ser que você adicione reivindicação de segurança do Zope a eles. Esse procedimento está for a do âmbito desse livro. Veja o Guia do Programador de Zope (Zope Developer's Guide) para mais informações.
Macros
Até agora, você tem visto como modelos de páginas podem ser usados para adicionar comportamento dinâmico a web pages individuais. Outra característica dos modelos de páginas é a capacidade de reusar elementos de look and feel em muitas páginas.
Por exemplo, com Modelos de Páginas, você pode ter um site que possui um padrão de look and feel. Não importa o "conteúdo" da página, ela terá um cabeçalho padrão, barra de rolagem, roda-pé, e/ou outros elementos da página. Esse é um requisito muito comum para web sites.
Você pode reusar elementos de apresentação nas páginas com macros. As Macros definem uma seção de uma página que pode ser reusada em outras páginas. Uma macro pode ser uma página inteira, ou apenas um pedaço de uma página que tem um cabeçalho ou um roda-pé. Depois que você define uma ou mais macros em um Modelo de Páginas, você pode usá-la em outro Modelo de Páginas.
Usando Macros
Você pode definir macros com atributos de tag similares às expressões TAL. Os atributos de tag da macro são expressões chamadas de Linguagem de Atributos de Tag de Expansão de Macro (Macro Expansion Tag Attribute Language - METAL). Aqui está um exemplo de definição de macro:
<p metal:define-macro="copyright">
Copyright 2001, <em>Foo, Bar, and Associates</em> Inc.
</p>
Essa expressão metal:define-macro define uma macro nomeada "copyright". A macro consiste de uma tag p e seus conteúdos (incluindo todas as tags contidas).
As macros definidas em um Modelo de Página são guardadas no atributo macro do modelo. Você pode usar macros de outro modelo de página ao referir-se a eles através do atributo macros do Modelo de Páginas no qual ele está definido. Por exemplo, suponha que a macro copyright está em um Modelo de Páginas chamado "master_page". Eis como usar a macro copyright de outro Modelo de Página:
<hr>
<b metal:use-macro="container/master_page/macros/copyright">
A Macro vem aqui
</b>
Neste modelo de páginas, a tag b será completamente substituída pela macro quando o Zope carregar a página:
<hr>
<p>
Copyright 2001, <em>Foo, Bar, and Associates</em> Inc.
</p>
Se você mudar a macro (por exemplo, se o proprietário do copyright mudar de nome) então todo o Modelo de Páginas que usa a macro irá automaticamente refletir a mudança.
Veja como a macro é identificada por uma expressão path usando a expressão metal:use-macro. A expressão metal:use-macro substitui o elemento da expressão pela macro nomeada.
Detalhes da Macro
As expressões metal:define-macro, e metal:use-macro são muito simples. Porém existem algumas sutilizas melhor mencionadas.
Um nome de macro deve ser único dentro do Modelo de Páginas no qual ele é definido. Você pode definir mais do que uma macro em um modelo, mas todas elas precisam ter nomes diferentes.
Normalmente você irá se referir a uma macro na expressão metal:use-macro com uma expressão path. Porém, você pode usar qualquer tipo de expressão que quiser desde de que a expressão retorne uma macro. Por exemplo:
<p metal:use-macro="python:here.getMacro()">
Replaced with a dynamically determined macro,
which is located by the getMacro script.
</p>
O uso expressões Python para alocar macros deixa você variar dinamicamente qual macro seu modelo usa.
Você pode usar a variável default com a expressão metal:use-macro:
<p metal:use-macro="default">
Este conteúdo permanence – nenhuma macro é usada
</p>
O resultado é o mesmo do que usar default com tal:content e tal:replace, o elemento da expressão não muda.
Se você tentar usar a variável nothing com metal:use-macro você terá um erro, já que nothing não é uma macro. Se você quer usar nothing para condicionalmente incluir uma macro, você deve em vez disso finalizar a expressão metal:use-macro com uma expressão tal:condition.
O Zope trata as macros primeiro quando interpreta seus modelos. Depois o Zope avalia as expressões TAL. Por exemplo, considere essa macro:
<p metal:define-macro="title"
tal:content="template/title">
template's title
</p>
Quando você usa essa macro ela irá inserir o título de um modelo no qual a macro é usada e não o título de um modelo no qual a macro está definida. Em outras palavras, quando você usa uma macro, é como copiar o texto de uma macro para dentro do seu modelo e depois carregar o seu modelo.
Se você marcar a opção Expandir macros quando editar (Expand macros when editing) na Aba Edit do Modelo de Páginas, então qualquer macros que você usar será expandido na fonte do seu modelo. Esse é a conduta padrão do Zope, e em geral é isso que você quer, já que isso permite que você edite uma página completa e válida. Porém, algumas vezes, especialmente quando você está editando no ZMI, ao invés de usar uma ferramenta de edição WYSIWYG, é mais conveniente não expandir as macros quando editar. Nesses casos, simplesmente desmarque a opção.
Usando Slots
As macros são muito mais úteis se você puder desconsiderar(override) partes delas quando usá-las. Você pode fazer isso definindo slots na macro que você pode preencher quando usar o modelo. Por exemplo, considere uma macro de side bar:
<p metal:define-macro="sidebar">
Links
<ul>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/support">Support</a></li>
<li><a href="/contact">Contact Us</a></li>
</ul>
</p>
Essa macro é boa, mas suponha que você gostaria de incluir alguma informação adicional nas sidebar em algumas páginas. Um jeito de fazer isso é usando slots:
<p metal:define-macro="sidebar">
Links
<ul>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/support">Support</a></li>
<li><a href="/contact">Contact Us</a></li>
</ul>
<span metal:define-slot="additional_info"></span>
</p>
Quando você usa essa macro você pode escolher preencher o slot dessa forma:
<p metal:fill-slot="container/master.html/macros/sidebar">
<b metal:fill-slot="additional_info">
Make sure to check out our <a href="/specials">specials</a>.
</b>
</p>
Quando você interpretar esse modelo a side bar irá incluir a informação extraque você forneceu no slot:
<p>
Links
<ul>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/support">Support</a></li>
<li><a href="/contact">Contact Us</a></li>
</ul>
<b>
Make sure to check out our <a href="/specials">specials</a>.
</b>
</p>
Veja como o elemento span que define o slot é substituído com o elemento b que preenche o slot.
Adequando a Apresentação Padrão
Adequando a Apresentação Padrão
Um uso comum de slot é para fornecer apresentação padrão que você pode adequar. No exemplo de slot da última seção, a definição de slot era apenas um elemento span vazio. Porém, você pode fornecer apresentação padrão em uma definição de slot. Por exemplo, considere essa macro para sidebar corrigida:
<div metal:define-macro="sidebar">
<p metal:define-slot="links">
Links
<ul>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/support">Support</a></li>
<li><a href="/contact">Contact Us</a></li>
</ul>
</p>
<span metal:define-slot="additional_info"></span>
</div>
Agora a sidebar está completamente adequada. Você pode preencher os links do slot para redefinir os links da sidebar. Porém, se você escolher não preencher o slot links então você terá links default que aparecerão dentro do slot.
Você ainda pode usar essa técnica adicional definindo slots dentro de slots. Isso permite que você passe por cima da apresentação padrão com um bom grau de precisão. Aqui está uma macro de sidebar que define slots dentro de slots:
<div metal:define-macro="sidebar">
<p metal:define-slot="links">
Links
<ul>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/support">Support</a></li>
<li><a href="/contact">Contact Us</a></li>
<span metal:define-slot="additional_links"></span>
</ul>
</p>
<span metal:define-slot="additional_info"></span>
</div>
Se você quiser adequar os links da sidebar pode ainda preencher o slot
links para desconsirar completamente os links, ou você pode preencher
o slot additional_links para inserir alguns links a mais depois dos links padrão.
Você pode aninhar quantos slots quiser.
Unindo METAL e TAL
Você pode usar expressões METAL e TAL juntas nos mesmos elementos. Por exemplo:
<ul metal:define-macro="links" tal:repeat="link here/getLinks">
<li>
<a href="link url"
tal:attributes="url link/url"
tal:content="link/name">link name</a>
</li>
</ul>
Já que expressões METAL são avaliadas antes que expressões
TAL, não há conflitos. Esse exemplo também é interessante
já que ele adapta(?) uma macro sem usar slots. A macro chama o Script
getLinks para determinar os links. Assim você pode adequar
os links do seu site para be redefinindo o Script getLinks de locais
diferentes dentro do seu site.
Nem sempre é fácil de compreender o melhor jeito de adequar look and feel em partes diferentes do seu site. Em geral você deve usar slots para passar por cima de elementos de apresentação e deve usar Scripts para fornecer conteúdo dinamicamente. No caso do exemplo dos links, é questionável se os links são conteúdo ou apresentação. Os Scripts provavelmente fornecerão uma solução mais flexível, especialmente se o seu site inclui objetos de conteúdo de link.
Conjunto das Macros da Página
Melhor do que usar macros para partes da apresentação dividida entre as páginas, você pode usar macros para definir páginas inteiras. Os Slots tornam isso possível. Aqui está um exemplo de macro que define uma página inteira:
<html metal:define-macro="page">
<head>
<title tal:content="here/title">O título</title>
</head><body>
<h1 metal:define-slot="headline"
tal:content="here/title">título</h1>
<p metal:define-slot="body">
Esse é o corpo da página.
</p>
<span metal:define-slot="footer">
<p>Copyright 2001 Fluffy Enterprises</p>
</span>
</body>
</html>
Essa macro define uma página com três slots, headline,
body, e footer. Veja como o slot headline
inclui uma expressão TAL para determinar o conteúdo do cabeçalho
dinamicamente.
Então você pode usar essa macro em modelos para diferentes tipos de conteúdo, ou diferentes partes do seu site. Por exemplo, aqui está como um modelo para novos itens deve usar essa macro:
<html metal:use-macro="container/master.html/macros/page">
<h1 metal:fill-slot="headline">
Press Release:
<span tal:replace="here/getHeadline">Headline</span>
</h1>
<p metal:fill-slot="body"
tal:content="here/getBody">
O corpo do novo item vem aqui
</p>
</html>
Esse modelo redefine o slot headline para incluir as palavras,
"Press Release" e chama o método getHeadline do
objeto corrente. Ele redefine também o slot body para chamar o método
getBody do objeto corrente.
A coisa mais importante (powerful) sobre essa abordagem é que agora você pode mudar a macro page e o modelo do press release será automaticamente atualizado. Por exemplo, você pode colocar o corpo da página em uma tabela e adicionar uma sidebar na esquerda e o modelo de press release irá usar automaticamente use esses novos elementos de apresentação.
Essa é uma solução muito mais flexível para controlar
o visual e feel das páginas depois da solução DTML standard_html_header
e standard_html_footer. De fato, o Zope trás um estoque
de modelos de páginas no quadro raiz chamado standard_template.pt
que inclui uma página inteira de macro com um slot head e body. Aqui
está como você deve usar essa macro em um modelo:
<html metal:use-macro="here/standard_template.pt/macros/page">
<div metal:fill-slot="body">
<h1 tal:content="here/title">Title</h1>
<p tal:content="here/getBody">Body text goes here</p>
</div>
</html>
O uso da macro standard_template.pt é mais similar ao uso
de outros conjuntos de macro na página. A única sutileza apontada
é a path ser usada/costumar para localizar a macro. Neste exemplo a path
começa com here. Isso significa que o Zope irá procurar o objeto
standard_template.pt usando uma aquisição de inicialização
no objeto que o modelo for aplicado. Isso permite que você adapte os modelos
de look and feel ao criar objetos custom standard_template.pt objects
em vários locais. Esse é exatamente o mesmo truque que você
usa para adequar look and feel ao passar por cima de standard_html_header
e standard_html_footer em localizações do site. Porém,
com standard_template.pt você tem mais escolhas. Você
pode escolher iniciar o path para a macro com root ou com container,
assim como com here também. Se o path começa com root então
você sempre irá obter o modelo padrão no qual está
localizado o quadro raiz. Se o path começa com container
então o Zope irá procurar por um modelo padrão usando inicialização
de aquisição no quadro em que o modelo for definido. Isso permite
que você adapte look feel dos modelos, mas não permite que você
customize o look e feel de objetos diferentes baseado em sua localização
no site.
Cacheando Modelos
Enquanto interpretar Modelos de Páginas normalmente é bem rápido, algumas vezes não é suficientemente rápido. Para páginas acessadas freqüentemente, ou páginas que levam muito tempo para carregar, você pode querer to trocar alguns comportamentos dinâmicos por velocidade. Cacheamento permite que você faça isso. Para mais infomação sobre cacheamento veja a seção "Gerenciamento de Cache" do Capítulo 3, "Objetos Básicos".
Você pode cachear Modelos de Páginas usando um gerenciador de cache do mesmo jeito que você pode cachear outros objetos. Para cachear um Modelo de Páginas, você deve associa-lo com um gerenciador de cache. Você pode fazer isso indo ao vizualizador Cache do seu Modelo de Páginas e selecionando o gerenciador de cache, ou indo até o vizualizador Associate do seu gerenciador de cache e localizando seu Modelo de Páginas.
Aqui está um exemplo de como cachear um Modelo de Páginas. Primeiro crie um script name baseado em Python long.py com esse conteúdo:
## Script (Python) "long.py"
##
for i in range(500):
for j in range(500):
for k in range(5):
pass
return 'Done'
O propósito desse script é apanhar uma grande quantidade de tempo de execução. Agora crie um Modelo de Páginas que use esse script, por exemplo:
<html>
<body>
<p tal:content="here/long.py">results</p>
</body>
</html>
Agora visualize essa página. Veja como ela leva um instante para carregar. Agora vamos melhorar radicalmente seu tempo de carregamento com cacheamento. Crie um Ram Cache Manager se você ainda não tem um. Se assegure de criá-lo dentro do mesmo quadro como seu Modelo de Páginas, ou em um nível mais alto. Agora visite o vizualizador Cache do seu Modelo de Páginas. Escolha o Gerenciador de Ram Cache que você criou e clique Save Changes (Salvar as Mudanças). Clique no link Cache Settings (Configurações de Cache) para ver como seu Gerenciador de Ram Cache está configurado. Como padrão, sua cache guarda objetos por uma (3600 segundos). Voc~e pode querer ajustar esse número dependendo da sua aplicação. Agora volte para seu Modelo de Páginas e visualize ela de novo. Ela deve levar um momento para carregar. Agora recarregue (atualizar) a página, e veja ela carregar imediatamente. Você pode recarregar a página de novo e de novo, e ela sempre carregarrá imediatamente já que agora a página está cacheada.
Se você mudar seu Modelo de Páginas, então isso será removido da cache. Então a próxima vez que você visualiza-lo, levará um momento para carregar. Mas depois disso vai carregar rapidamente já que será cacheado novamente.
Cacheamento é uma técnica simples mas muito poderosa para o melhoramento da performance. Você não tem que ser um gênio para usar cachamento e ele pode fornecer grandes aceleramentos. Seu tempo fica bem melhor usando cacheamento para aplicações com performance critica.
Utilidades do Modelo da Página
Os Modelos de Páginas do Zope são poderosos mas simples. Diferente de DTML, Modelos de Páginas não lhe oferecem um monte de características de comodidade para coisas como paginação, drawing trees, sorting, etc. O criador do Modelo de Páginas queria mantê-los simples. Porém, você pode sentir falta de alguns dos benefícios embutidos que DTML fornece. Para se dirigir a essas necessidades, o Zope possui utilidades designadas para aumentar os Modelos de Páginas.
Paginando Grandes Conjuntos de Informação
Quando um usuário pesquisa um banco de dados e obtém centenas de resultados, freqüentemente é melhor mostrá-los em várias páginas com apenas vinte resultados por página, ao invés de colocar todos os resultados uma única página. Dividir grandes listas em listas menores é chamado de paginação.
Diferente de DTML, que fornece páginação incorporada dentro da linguagem, Modelos de Páginas suportam paginação usando um objeto especial Batch que vem do módulo utilitário ZTUtils. Veja Appendix B, "Referencia API", para mais informação sobre o módulo Python ZTUtils.
Aqui está um exemplo simples mostrando como criar um objeto Batch:
<ul tal:define="lots python:range(100);
batch python:modules['ZTUtils'].Batch(lots,
size=10,
start=0)">
<li tal:repeat="num batch"
tal:content="num">0
</li>
</ul>
Esse exemplo carrega uma lista com 10 itens (neste caso, do número 0 até 9). O objeto Batch corta uma lista longa em grupos ou montes. Neste caso ele quebra uma lista com uma centena de itens em montes de dez itens.
Você pode mostrar um monte diferente de dez itens passando um número inicial diferente:
<ul tal:define="lots python:range(100);
batch python:modules['ZTUtils'].Batch(lots,
size=10,
start=13)">
Esse batch começa com o décimo quarto item e termina com o vigésimo terceiro. Em outras palavras, ele mostra os números entre 13 e 22. é importante notar que o argumento start do batch é o index (índice) do primeiro item. Os índices contam a prtir de zero, ao invés de contra a partir do 1. Então indexa 13 pontos a partir do décimo quarto item na seqüência. Python usa indices para se referir a listas de items.
Normalmente quando você usa batches você irá querer incluir elementos de navegação na página para permitir que os usuários se moverem de batch em batch. Aqui está um exemplo de paginação full-blow que mostra como navegar entre batches:
<html>
<head>
<title tal:content="template/title">The title</title>
</head>
<body tal:define="employees here/getEmployees;
start python:path(request/start) or 0;
batch python:modules['ZTUtils'].Batch(employees,
size=10,
start=start);
previous python:batch.previous;
next python:batch.next"> <p>
<a tal:condition="previous"
tal:attributes="href string:${request/URL0}?start:int=${previous/first}"
href="previous_url">previous</a>
<a tal:condition="next"
tal:attributes="href string:${request/URL0}?start:int=${next/first}"
href="next_url">next</a>
</p> <ul tal:repeat="employee batch" >
<li>
<span tal:replace="employee/name">Bob Jones</span>
makes $<span tal:replace="employee/salary">100,000</span>
a year.
</li>
</ul> </body>
</html>
Esse exemplo iterates sobre batches (montes) de resultados do Método
ZSQL getEmployees. Ele mostra um link de previous (anterior)
e next (próximo) se necessário para que você possa
ver todos os resultados de um batch de cada vez.
Dê uma olhada na expressão tal:define no elemento
body. Ela define um grupo de variáveis de paginação. A
variável employees é potencialmente uma grande lista
de objetos empregados retornada pelo Método ZSQL getEmployees.
A Segunda variável, start, é configurada para o valor
de request/start ou para zero se não há variável
start na pesquisa. A variável start contém
endereços de onde você está na lista de empregados. A variável
batch é um monte batch de dez itens das listas de empregados.
A batch começa no local especificado pela variável start.
As variáveis previous e next se referem aos
montes anteriores e os próximos (if any). Já que todas as varíveis
estão definidas no elemento body, elas estão disponíveis
para todos os elementos dentro do corpo da página.
Depois vamos olhar os links de navegação. Eles criam hyperlinks
para browsear os batches anterior e próximo. A expressão tal:condition
primeiro testa para ver se há um batch de anterior e próximo.
Se há um bacth de anterior ou próximo, então o link é
carregado, se não, não há nenhum link. A expressão
tal:attributes cria um link para os bacthes anterior e próximo.
O link é simplesmente a URL ou a página corrente (request/URL0)
contendo uma string de pesquisa que indica o começo do índice
do batch. Por exemplo, se o batch corrente começa com índice 10,
então o batch anterior começará com um índice 0.
a variável first do batch fornece seu índice de começo
(staring index), então, nesse caso, previous.start será
0.
Não é importante entender completamente como funciona esse exemplo.
Simplesmente copie ele, ou use um exemplo de paginação criado
pelo Z Search Interface. Depois quando você quiser fazer uma paginação
mais complexa você pode experimentar trocar o código do exemplo.
Não esqueça de consultar o Appendix B, "Referência
API" para mais informações sobre o módulo ZTUtils
e objetos Batch.
Utilidades Diferentes
O Zope fornece uma dupla de módulos Python que podem ser úteis
no uso de Modleos de Páginas. Os módulos string,
math e random podem ser usados em expressões
Python para o formatação de strings, funções matemáticas
e geração de números pseudo-randômicos. Esses mesmos
módulos estão disponíveis para from DTML e scripts baseados
em Python. Veja o Appendix B, "Referência API " para mais informação
sobre esses módulos.
O módulo Products.PythonScripts.standard foi designado
a fornecer utilidades para scripts baseados em Python, mas também é
útil para Modelos de Páginas. Ele inclui várias funções
de formatação de strings e números. Veja o Appendix B,
"Referência API" para mais informação.
Como foi mencionado anteriormente neste capítulo, o módulo sequence
fornece uma função sort muito útil. Veja o
Appendix B, "Referência API" para mais detalhes.
Finalmente o módulo AccessControl inclui uma função
e uma classe que você irá precisar se quiser testar o acesso e
obter o usuário autenticado. Veja o Appendix B, "Referência
API" para mais informação.
Conclusão
Esse capítulo aborda todos os cantos e todas as fendas sobre Modelos de Páginas e depois de lê-lo você poderá sentir se um pouco oprimido. Mas não se preocupe, você não precisa saber tudo que foi exposto neste capítulo para usar efetivamente Modelos de Páginas. Você deve entender os diferentes tipos de path e macros, mas você pode revisar o resto do material quando precisa-lo. As características avançadas que você tem que aprender neste capítulo estarão lá para você quando você precisar. É incentivador saber que quando você está pronto você pode fazer alguns truques muito impressionantes com Modelos de Páginas.