askama icon indicating copy to clipboard operation
askama copied to clipboard

Compilation error when including template that contains block

Open OskarPersson opened this issue 3 years ago • 8 comments

When I try to include a template that contains a block definition from another template, I get the error below.

use askama::Template;

#[derive(Template)]
#[template(path = "index.html")]
struct IndexTemplate<'a> {
    name: &'a str,
}

fn main() {
    let hello = IndexTemplate { name: "world" };
    println!("{}", hello.render().unwrap());
}

index.html

{% include "hello.html" %}

hello.html

{% block foo %}{% endblock %}

Hello, {{ name }}!

Output

error: no block ancestors available
 --> src/main.rs:3:10
  |
3 | #[derive(Template)]
  |          ^^^^^^^^
  |
  = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: no method named `render` found for struct `IndexTemplate` in the current scope
  --> src/main.rs:11:26
   |
5  | struct IndexTemplate<'a> {
   | ------------------------ method `render` not found for this
...
11 |     println!("{}", hello.render().unwrap());
   |                          ^^^^^^ method not found in `IndexTemplate<'_>`
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `render`, perhaps you need to implement it:
           candidate #1: `Template`

For more information about this error, try `rustc --explain E0599`.
error: could not compile `askama-test` due to 2 previous errors

OskarPersson avatar Mar 10 '22 16:03 OskarPersson

You wrote {% include %} when you wanted to use {% extends %}: https://djc.github.io/askama/template_syntax.html#template-inheritance

{% include %} in Askama is just like #include in C: The source of the included file gets "pasted" into the including file. The error tells you that cannot use {% block %} without {% extends %}. But, yeah, the error message could be better.

Kijewski avatar Mar 10 '22 17:03 Kijewski

No I actually want it to be included in this case. In a more advanced example I would include the hello.html template in multiple other templates and have other templates extend from hello.html and implement the foo block.

OskarPersson avatar Mar 10 '22 17:03 OskarPersson

You are describing exactly what {% extends %} does. Maybe Jinja2's readme is more clear to you? https://jinja2docs.readthedocs.io/en/stable/templates.html#template-inheritance

Kijewski avatar Mar 10 '22 17:03 Kijewski

Hmm... I'm still not entirely convinced that {% include %} is the wrong choice here for me but let's say I go with {% extends %} instead. How would you solve the following then?

I still have the same main.rs but the following templates to better illustrate my problem:

index.html

<div>
  <h1>Welcome</h1>
  {% include "hello_foo.html" %}
</div>

hello_base.html

<div>
  <p>Below me is the header</p>
  {% block header %}{% endblock %}
  <p>Above me is the header</p>
</div>

Hello, {{ name }}!

hello_foo.html

{% extends "hello_base.html" %}

{% block header %}foo{% endblock %}

Because with this I get another error:

error: extend blocks only allowed at the top level
 --> src/main.rs:3:10
  |
3 | #[derive(Template)]
  |          ^^^^^^^^
  |
  = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: no method named `render` found for struct `IndexTemplate` in the current scope
  --> src/main.rs:11:26
   |
5  | struct IndexTemplate<'a> {
   | ------------------------ method `render` not found for this
...
11 |     println!("{}", hello.render().unwrap());
   |                          ^^^^^^ method not found in `IndexTemplate<'_>`
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `render`, perhaps you need to implement it:
           candidate #1: `Template`

For more information about this error, try `rustc --explain E0599`.
error: could not compile `askama-test` due to 2 previous errors

OskarPersson avatar Mar 10 '22 21:03 OskarPersson

Testing the exact same templates with Jinja2 (version 3.0.3) works as expected and generates the correct output:

main.py

from jinja2 import Environment, FileSystemLoader, select_autoescape

env = Environment(
    loader=FileSystemLoader("templates"),
    autoescape=select_autoescape()
)

template = env.get_template("index.html")
print(template.render(name="world"))

Output (with manual fix to indentation fixes for better visualization)

<div>
  <h1>Welcome</h1>
  <div>
    <p>Below me is the header</p>
    foo
    <p>Above me is the header</p>
  </div>

  Hello, world!
</div>

OskarPersson avatar Mar 12 '22 00:03 OskarPersson

Seems like I've landed at the same limitation as described in https://github.com/djc/askama/issues/572

OskarPersson avatar Mar 12 '22 00:03 OskarPersson

I don't know why this restriction exists. Maybe you could comment out https://github.com/djc/askama/blob/0b376b439f759613966916787b613616627bb3f9/askama_shared/src/generator.rs#L445-L447 and tell us what works and what breaks then?

Kijewski avatar Mar 12 '22 00:03 Kijewski

Then I get the first error again (because of the {% include "hello_foo.html" %} in index.html):

error: no block ancestors available
 --> src/main.rs:3:10
  |
3 | #[derive(Template)]
  |          ^^^^^^^^
  |
  = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: no method named `render` found for struct `IndexTemplate` in the current scope
  --> src/main.rs:11:26
   |
5  | struct IndexTemplate<'a> {
   | ------------------------ method `render` not found for this
...
11 |     println!("{}", hello.render().unwrap());
   |                          ^^^^^^ method not found in `IndexTemplate<'_>`
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `render`, perhaps you need to implement it:
           candidate #1: `Template`

For more information about this error, try `rustc --explain E0599`.
error: could not compile `askama-test` due to 2 previous errors

OskarPersson avatar Mar 12 '22 11:03 OskarPersson