简体   繁体   中英

Jinja2 Output Markdown Frontmatter to List

I have a folder of Markdown files. Each file contains a block of YAML frontmatter. I am trying to output the title's from each file's frontmatter into a Jinja2 template, and list them all in a HTML file.

I have no issue displaying the titles without Jinja2, but it all falls apart when I try to output to my Jinja2 template.

Here's an example of the Markdown files I'm working with, and the title: item I am trying to list:

---
title: Test
date: 2020-03-26
---

## Test Markdown

Here's the Python code I am using. I'm using the python-frontmatter module to extract the frontmatter from each Markdown post.

Using the frontmatter module it's really easy to select the title and display it on the terminal, but I'm not getting anywhere with the Jinja2 template. content.metadata is a dict.

import frontmatter
import jinja2
import glob

# Initialise Jinja2:
jinja2_env = jinja2.Environment(
    loader=jinja2.FileSystemLoader("templates"),
)

# Get list of posts:
posts = glob.glob("posts/*.md")

def build():

    with open("test.html", "w", encoding="utf-8") as index_file:
        for post in posts:
            content = frontmatter.load(post)

            # Prints titles to the terminal the way I want to output them in the Jinja template:
            print(content.metadata["title"])

            # Jinja output:
            template = jinja2_env.get_template("test.html.j2")
            rendered = template.render(frontmatter=content.metadata)
            index_file.write(rendered)

build()

My Jinja2 template looks like this:

<ul>
{% for key, value in frontmatter.items() %}
    <li><a href="">{{ value.title() }}</a></li>
{% endfor %}
</ul>

This doesn't work at all, and I get an error jinja2.exceptions.UndefinedError: 'datetime.datetime object' has no attribute 'title' . If I remove .title() then the HTML file that gets created ends up looping through the dicts but outputs the full template for each one:

<ul>

    <li><a href="">Test Title 1</a></li>

    <li><a href="">2020-10-21 10:00:20</a></li>

</ul><ul>

    <li><a href="">Test Title 2</a></li>

    <li><a href="">2019-06-09 17:42:12</a></li>

</ul><ul>

    <li><a href="">Test Title 3</a></li>

    <li><a href="">2019-06-09 17:42:12</a></li>

</ul>

I'm at the limits of my Python knowledge here, so any help on resolving this would be great. What I want at the end of it all is an HTML file that outputs each file's title like this:

<ul>
    <li><a href="">Test Title 1</a></li>
    <li><a href="">Test Title 2</a></li>
    <li><a href="">Test Title 3</a></li>
</ul>
<ul>
{% for key, value in frontmatter.items() %}
    <li><a href="">{{ value.title() }}</a></li>
{% endfor %}
</ul>

This is wrong. Like the error message says, you're calling title() on a datetime object (your date front matter).

Your loop is iterating over every key (title, then date) in the front matter, as well as the value .

<ul>
    <li><a href="">{{ frontmatter.title }}</a></li>
    <li>{{ frontmatter.date }}</li>
</ul>

Of course, this is only going to show you the title for one of your source files, because you are looping over every post and rendering them as entirely separate templates:

for post in posts:

You want to render 1 template, so remove the for loop around your call to render() and pass it all of your posts:

rendered = template.render(
    posts=posts,
    posts_meta=[frontmatter.load(post).metadata for post in posts]
)

... and loop over them in your template:

<ul>
{% post_meta in posts_meta %}
    <li><a href="">{{ post_meta.title }}</a></li>
{% endfor %}
</ul>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM