askama

repository·main·Indexed 22 days ago

https://github.com/askama-rs/askama

A type-safe template rendering engine for Rust that uses Jinja-like syntax. Askama generates Rust code from templates at compile time to ensure templates are checked against data structures for maximum performance and safety. It supports template inheritance, control flow, macros, and custom escapers. The project includes auxiliary crates such as askama_escape for lightweight HTML/XML escaping and askama_macros for procedural macro processing.

Tokens
32.1K
Snippets
135
Records
162
Agent score
77%

What's inside askama

  1. Concatenate strings using the `~` operator

    main

    Instead of multiple {{ a }}{{ b }} blocks, you can use the tilde ~ operator for string concatenation: {{ a ~ b ~ c }}.

    Important: The ~ operator must be surrounded by spaces to prevent confusion with the whitespace control operator.

    {{ a ~ b ~ c }}
  2. Handle undefined or default values with assigned_or and defined_or

    main

    Askama provides two primary filters for handling missing or default values, which are more expressive than the Jinja-compatible |default filter.

    • |assigned_or(fallback): Use this when the left-hand side is in a "default" state (e.g., an empty string "", 0, None, or an Err(_) result). It returns the fallback value in these cases.
    • |defined_or(fallback): Use this specifically for identifiers. It returns the fallback value only if the identifier is undefined (not declared in the scope).
    {# assigned_or for default states #}
    {% let greeting = Some("Hello") %}
    {{ greeting.as_ref() | assigned_or("Hi") }} {# Output: Hello #}
    
    {# defined_or for undefined identifiers #}
    {{ greeting | defined_or("Hi") }} {# Output: Hello if greeting is defined, else Hi #}
  3. Using Filters and Filter Blocks

    main

    Filters post-process values using the pipe symbol (|). They can be chained, where the output of one filter is passed to the next.

    Filter Blocks: You can apply a filter to an entire block of content using {% filter ... %} ... {% endfilter %}.

    To define custom filters, include a module named filters in the scope of the context deriving the Template implementation. Built-in filters take precedence in case of name collisions.

    // Chained filters
    {{ "{:?}"|format(name|escape) }}
    
    // Filter block
    {% filter lower %}
      {{ t }} / HELLO / {{ u }}
    {% endfilter %}
    
    // Chained filter block
    {% filter lower|capitalize %}
      {{ t }} / HELLO / {{ u }}
    {% endfilter %}
  4. Check if a variable is defined

    main

    Use is defined or is not defined to check for the existence of a variable.

    Limitation: Due to proc-macro constraints, you can only check if a variable declared in the template or a field of the current type exists. You cannot check if a nested field or a function is defined (e.g., {% if x.y is defined %} will fail to compile).

    {% if x is defined %}
      x exists!
    {% endif %}
  5. Call functions and methods in templates

    main

    Askama allows calling functions and methods within templates.

    • Methods: If you provide only a name, Askama assumes it is a method on the current context (equivalent to self.method()).
    • Functions: To call a function from the current module, use the self:: path (equivalent to self::function()).
    • External Paths: You can call functions from other modules using full paths (e.g., super::b::f()).
    {# Method call #}
    {{ method() }}
    
    {# Function call from current module #}
    {{ self::function() }}
    
    {# External path call #}
    {{ super::b::f() }}
  6. Use expressions and operators in Askama templates

    main

    Askama supports string and integer literals, and almost all binary operators supported by Rust (arithmetic, comparison, and logic). It follows Rust's operator precedence. You can group expressions using parentheses.

    Note on Bitwise Operators: To avoid confusion with filter expressions, the binary AND, OR, and XOR operators are renamed to bitand, bitor, and xor respectively.

    Note on HTML Escaping: Special characters &, <, and > are escaped by default unless you use the | safe filter or disable escaping for the template.

    {{ 3 * 4 / 2 }}
    {{ (4 + 5) % 3 }}
    
    {# Bitwise operators #}
    {% if my_bitset bitand 1 != 0 %}
        It is set!
    {% endif %}
  7. What features are supported in Askama templates

    main

    Askama supports a variety of Jinja-inspired template features, including:

    • Template inheritance: Define base layouts and extend them.
    • Control flow: Loops, if/else statements, and include support.
    • Macros: Reusable template logic.
    • Variables: Access data via struct fields (note: variables are immutable within the template).
    • Filters: Access built-in filters or define your own.
    • Whitespace control: Use - markers to suppress whitespace.
    • Escaping: Opt-out of HTML escaping when necessary.
    • Customization: Ability to customize syntax.
  8. Accessing Variables and Constants in Templates

    main

    Variables are provided by the template's context type. You can access fields or methods using dot notation (e.g., {{ user.name }}).

    To use Rust constants in your templates, use their full path starting from crate::.

    // Rust side
    pub const MAX_NB_USERS: usize = 2;
    
    // Template side
    <p>The user limit is {{ crate::MAX_NB_USERS }}.</p>
    {% set value = 4 %}
    {% if value > crate::MAX_NB_USERS %}
        <p>{{ value }} is bigger than MAX_NB_USERS.</p>
    {% else %}
        <p>{{ value }} is less than MAX_NB_USERS.</p>
    {% endif %}