Keats / tera

A template engine for Rust based on Jinja2/Django
http://keats.github.io/tera/
MIT License
3.36k stars 280 forks source link

如何调用异步标签,目前是不是不支持异步标签? #877

Open sunkaifei opened 7 months ago

sunkaifei commented 7 months ago

一个网站里有很多模块,首页要推荐很多栏目列表,这些列表要从数据库读取,例如文章的推荐类型就有最新的,推荐的,热门的等等,如果这个标签可以通过设置的参数调用各个所需的内容就行了

Keats commented 7 months ago

Can you translate in English?

sunkaifei commented 7 months ago

Hello, I understand that you are facing some issues with the tera template engine in the actix_web framework. Here is a translation of your previous message into English:

For example, in a Java program, there is a freemarker template plugin that defines a module's tag at the Java backend. For instance, it can be an article list tag that allows setting various parameters. Then, in the template, you can directly call this tag with parameters to retrieve the desired content. This tag can be global.

Currently, I am using actix_web and the tera engine. I encountered the following issues:

The tera.register_function method cannot invoke asynchronous functions, such as retrieving data from a database. It seems that in actix_web, the global usage of tags requires calling them again in each controller for them to take effect. The template reload feature does not seem to work when set in actix_web. It requires calling the template setup function every time. Is there a way to set it globally in the main function?

sunkaifei commented 7 months ago

If you are using an asynchronous function to retrieve an article list and the returned content can be of various types, but Tera only accepts Result as the output type, you will need to handle the conversion from different types to Value within your code.

`pub async fn article_tags(args: &HashMap<String, Value>) -> Result {

let mut param =ArticlesPageRequest{
    category_id: None,
    user_id: None,
    status: None,
    page_no: 1,
    page_size: 10,
};

if let Some(category_id) = args.get("categoryId") {
    param.category_id = Some(category_id.as_i64().unwrap() as u64);
}
if let Some(user_id) = args.get("userId") {
    param.user_id = Some(user_id.as_i64().unwrap() as u64);
}
if let Some(status) = args.get("status") {
    param.status = Some(status.as_i64().unwrap() as i8);
}

let mut result: Vec<ArticlesListData> = Vec::new();
match article_service::get_by_page(param).await {
    Ok(data_op) => {
        result = data_op.records.iter().map(|article| {
            ArticlesListData {
                id: article.id.clone(),
                short_url: article.short_url.clone(),
                category_id: article.category_id.clone(),
                category_ids: article.category_ids.clone(),
                user_id: article.user_id.clone(),
                title: article.title.clone(),
                short_title: article.short_title.clone(),
                title_image: article.title_image.clone(),
                author: article.author.clone(),
                original_link: article.original_link.clone(),
                description: article.description.clone(),
                content: article.content.clone(),
                count_comment: article.count_comment.clone(),
                count_view: article.count_view.clone(),
                count_love: article.count_love.clone(),
                count_digg: article.count_digg.clone(),
                count_burys: article.count_burys.clone(),
                count_follow: article.count_follow.clone(),
                isclose: article.isclose.clone(),
                iscomment: article.iscomment.clone(),
                iscommentshow: article.iscommentshow.clone(),
                isposts: article.isposts.clone(),
                isrecommend: article.isrecommend.clone(),
                update_time: article.update_time.clone(),
            }
        }).collect();

        let json_value: Value = to_value(result)?;
        return Ok(json_value);
    }
    Err(_) => {}
}`
` 13 tera.register_function("article_tags", article_tags); ----------------- ^^^^^^^^^^^^ expected Result<Value, Error>, found future
required by a bound introduced by this call
note: calling an async function returns a future --> src\core\service\templates_service.rs:13:44 13 tera.register_function("article_tags", article_tags); ^^^^^^^^^^^^ = note: required for fn(&HashMap<String, Value>) -> impl Future<Output = Result<Value, Error>> {article_tags} to implement Function = note: the full type name has been written to 'E:\rustwork\actix-admin\target\debug\deps\actix_admin.long-type-17683279296791569248.txt' note: required by a bound in Tera::register_function --> C:\Users\kaife.cargo\registry\src\github.com-1ecc6299db9ec823\tera-1.19.1\src\tera.rs:668:33
668 pub fn register_function<F: Function + 'static>(&mut self, name: &str, function: F) {
^^^^^^^^ required by this bound in Tera::register_function

help: consider awaiting on the Future | 13 | tera.register_function("article_tags", article_tags.await); | ++++++ `

Keats commented 7 months ago

Tera doesn't support async tests/functions/filters no

sunkaifei commented 7 months ago

Is there a plan to support asynchronous calling of tags?

Keats commented 7 months ago

No

dw0616 commented 4 months ago

@sunkaifei async functions你有没有实现出来? 我另起一个线程,然后使用futures::executor::block_on加载异步调用数据,但是有时会卡死。

sunkaifei commented 4 months ago

@dw0616 没有,我技术能力有限,没搞定就没搞了

sunkaifei commented 4 months ago

@dw0616 作者好像没有实现这个功能想法,哈哈

sunkaifei commented 1 month ago

@sunkaifei async functions你有没有实现出来? 我另起一个线程,然后使用futures::executor::block_on加载异步调用数据,但是有时会卡死。

哥们,你的问题解决了吗?你具体怎么使用的,能给个例子吗?