home contents changes options help subscribe edit (external edit)

This is a style guide containing suggested best practices for writing Page Templates. It is not intended to be an authoritative set of rules. But this should be a good starting point.

To quote from PEP 8: Style Guide for Python Code :

A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is most important.

But most importantly: know when to be inconsistent - sometimes the style guide just doesn't apply. When in doubt, use your best judgement. Look at other examples and decide what looks best. And don't hesitate to ask!

Indentation and Line Breaks

tal: attributes with multiple bindings (i.e. tal:define, tal:attributes) should have each binding on a separate line, with the second and following bindings starting at the same column as the first binding.

Example:

     Bad:

       <span tal:define="var1 context/getVar1; var2 request/var2 | context/var2;
            var3 python:str(context.var3).split()"
       >
          ...
       </span>

     Better:  

       <span tal:define="var1 context/getVar1;
                         var2 request/var2 | context/var2;
                         var3 python:str(context.var3).split()"
       >
          ...
       </span>

     Best:

       <span tal:define="
           var1 context/getVar1;
           var2 request/var2 | context/var2;
           var3 python:str(context.var3).split()
       ">
          ...
       </span>

(The last version is preferred because it's typically easiest to do in a text editor, and the lines are shorter.)

Do not place metal: or tal: attributes on the same line as any other attribute (normal HTML, or even in the same namespace). Example:

       bad:

       <a href="." tal:attributes="href container/absolute_url">My container</a>

       better:

       <a href="." 
          tal:attributes="href container/absolute_url">My container
       </a>

Order of Attributes

tal: attributes should come in their "execution order", per the TAL specification The order is:

  • tal:define
  • tal:condition
  • tal:repeat
  • tal:content or tal:replace (an element may have only one of these)
  • tal:attributes
  • tal:omit-tag

Example:

       <a tal:define="x context/getSomeObject"
          tal:condition="x"
          tal:content="x/title_or_id"
          tal:attributes="href x/absolute_url_path"
       >
           Title Goes Here 
       </a>

On a given element, "normal" HTML attributes should come first, then metal: attributes, then tal: attributes.

Example:

      Bad:

        <span tal:content="context/title"
              metal:fill-slot="main" 
              class="big"> 
          ...
        </span> 

      Better:

        <span 
            class="big"
            metal:fill-slot="main"
            tal:content="context/title"
        > 
         ...
        </span> 

Use "context", not "here"

The "here" namespace should be deprecated in favor of "context." You will find that older templates (prior to Zope 2.7) use "here" liberally. For Zope 3, if not before, "here" will be removed. If you are using Zope 2.7 or higher, start using "context" in your templates now.

Example:

      Bad:

        <h1 tal:content="here/title">The Title</h1>

      Better:

        <h1 tal:content="context/title">The Title</h1>

Factoring for Readability

TALES expressions which can't be fit onto a single line, using the guidelines above, are definitely suspect: consider moving that logic out into a Python script, and replacing the expression with a simple path expression which calls the new script.

The script should be given a name which clearly and concisely communicates its purpose.

If there are a large number of expressions to refactor, it may be worthwhile to put the logic in a simple Product instead. (It would be nice if we had Zope3's "Persistent Modules").

Suggested Preferred Idioms

Always write an end tag for non-EMPTY elements, and do not write end tags for EMPTY elements. (The EMPTY elements in HTML are: br, hr, img, input, base, meta, link, area, param, col.) Examples:

      Bad:

       <span tal:content="context/foo" />

       <img tal:replace="context/barimage"></img>

      Better:

       <span tal:content="context/foo"></span> 

       <img tal:replace="context/barimage" />

Use path expressions whenever possible. For simple string substitution, use a string expression. Only use python expressions if you cannot use either a path or string expression.

Examples:

      Bad:

        <tal:block replace="python:context.getDate()"> The Date </tal:block>

        <a tal:attributes="href python:context.absolute_url() + "/foo"> Foo </a>

      Better:

        <tal:block replace="context/getDate"> The Date </tal:block>

        <a tal:attributes="href string:${context/absolute_url}/foo"> Foo </a>

Use "not:" to negate non-Python expressions. Use the python "not" operator within Python expressions. This way, you limit the number of different systems you need to keep in mind while reading the expression: either Python or TALES, not both.

Examples:

      Bad:

        <span tal:condition="not:python:a==b">...</span>

        <span tal:condition="python:not context.foo()">...</span>

      Better:

        <span tal:condition="python:not a==b">...</span>

        <span tal:condition="not:context/foo">...</span>

Your unrendered template should closely reflect the rendered version - it should have the same HTML tags, even if some of them will be replaced. Accordingly, use "tal:block replace" whenever the result of the expression is not an HTML tag. (NOTE: if your HTML editor does not preserve unrecognized tags, you may have to use "tal:omit-tag" or "tal:replace" instead of "tal:block".)

Examples:

      Bad:

        <span tal:replace="string: Hi there!"></span>

      Better:

        <tal:block replace="string: Hi there!" />

     Or, if you use an editor that does not preserve "tal:block", you could write
     that as:

        <span tal:replace="string: Hi there!"></span>

Conversely, use an HTML tag with "tal:replace" when the result of the expression will be the same HTML element.

Examples:

      Bad:

        <tal:block replace="context/someSpanTag"> This will be replaced with a SPAN tag. </tal:block>

      Bad:

        <p tal:replace="context/someSpanTag"> This will be replaced with a SPAN tag. </p>

      Better:

        <span tal:replace="context/someSpanTag"> This will be replaced with a SPAN tag. </span>



subject:
  ( 25 subscribers )