使用 Option<String> 和 Display 的其他非实现者,以及 assama::Template

问题描述 投票:0回答:1

我想使用相同的结构从

sqlx
接收数据并将该数据传递到
askama::Template
。 (我会有很多这样的结构。)

sqlx
让我使用
Option<String>
,因为该列是可为空的 varchar。
askama::Template
禁止我使用
Option<String>
,因为它需要
Display
特征。

如果我尝试从包含

askama::Template
的结构中派生
Option<String>
,我会收到错误:

error[E0277]: `std::option::Option<std::string::String>` doesn't implement `std::fmt::Display`
  --> src/root.rs:35:10
   |
35 | #[derive(Template)]
   |          ^^^^^^^^ `std::option::Option<std::string::String>` cannot be formatted with the default formatter
   |
   = help: the trait `std::fmt::Display` is not implemented for `std::option::Option<std::string::String>`, which is required by `&std::option::Option<std::string::String>: std::fmt::Display`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
   = note: this error originates in the macro `$crate::format_args` which comes from the expansion of the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)

如何将一个结构体用于这两个目的?

这是我当前的解决方法,使用两个类似的结构和

From
的实现:

use askama::Template;
use axum::{extract::Query, Extension};
use chrono::{DateTime, Utc};
use serde::Deserialize;
use sqlx::PgPool;
//use tracing::debug;

#[derive(sqlx::FromRow, Debug)]
pub struct LatestProvisioningRequest {
    uid: String,
    ts: DateTime<Utc>,
    ip: Option<String>,
}

pub struct LatestProvisioningRequestForTemplate {
    uid: String,
    ts: DateTime<Utc>,
    ip: String,
}

impl From<LatestProvisioningRequest> for LatestProvisioningRequestForTemplate {
    fn from(value: LatestProvisioningRequest) -> Self {
        let ip = match value.ip {
            Some(str) => str,
            None => "".to_owned(),
        };
        LatestProvisioningRequestForTemplate {
            uid: value.uid,
            ts: value.ts,
            ip
        }
    }
}

#[derive(Template)]
#[template(path = "root.html")]
pub struct RootTemplate {
    requests: Vec<LatestProvisioningRequestForTemplate>
}

// Used to extract the "next" field from the query string.
#[derive(Debug, Deserialize)]
pub struct RootQueryParameters {
    // TODO
}

pub async fn fetch_unenrolled(pool: &PgPool) -> Vec<LatestProvisioningRequestForTemplate> {
    let rows = sqlx::query_as::<_, LatestProvisioningRequest>(r#"SELECT * FROM latest_provisioning_requests"#)
    .fetch_all(pool)
    .await
    .unwrap();

    rows.into_iter().map(|x| x.into()).collect()
}

pub async fn root(
    Extension(pool): Extension<PgPool>,
    Query(RootQueryParameters {}): Query<RootQueryParameters>
) -> RootTemplate {

    RootTemplate {
        requests: fetch_unenrolled(&pool).await
    }
}
rust struct rust-sqlx askama
1个回答
0
投票

为了让一切保持简单,我们假设我们有以下内容

struct Page

use askama::Template;

#[derive(Template, Clone, Debug)]
#[template(path = "page.html.jinja")]
pub struct Page {
    text: Option<String>,
}

现在我们希望始终渲染

text
(如果是
Some
)或渲染 (如果是
None
)。

我们可以通过几种方式做到这一点,您可以使用

match

{% match self.text %}
    {% when Some with (text) %}
        {{ text }}
    {% else %}
{% endmatch %}

您还可以实现一个实用程序

fn display_some()
并调用它:

pub fn display_some<T>(value: &Option<T>) -> String
where
    T: std::fmt::Display,
{
    value
        .as_ref()
        .map(|value| value.to_string())
        .unwrap_or_default()
}

请注意,这是故意使用

&Option<T>
,而不是
Option<T>
Option<&T>
,Askama 自动参考值。

模板:

{{ self::display_some(self.text) }}

您还可以实现自定义过滤器,但我刚刚遇到了一个我不认识的问题。我是 Askama 的(被动)维护者之一,所以我会调查一下。

© www.soinside.com 2019 - 2024. All rights reserved.