Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask - use decorator and route param to render data with custom jinja2 tag

I'd like to add metadata tags to a Jinja template via combination of decorator and route param:

view:

@meta_tags(foo='bar', ping='pong')
@app.route('/some-route/<slug>')
def action(slug):
    return render_template('action.html')

template:

<html>
    <head>
        <title>Foo</title>
        {{ meta_tags }}
        <!-- 
        should render:
        <meta name="slug" content="[actual-slug]" />
        <meta name="foo" content="bar" />
        <meta name="ping" content="pong" />
        -->
    </head>
    ...

Goals:

  • Render each of the kwargs into its own meta tag.
  • Render the page-specific slug into another custom tag.

I realize one way to accomplish this involves registering with @app.context_processor, but then I also want to snag and use the dynamic slug part and create a custom jinja tag that'll render the <meta> html part.

What's an idiomatic Flask way to tackle? thanks.

like image 467
sa125 Avatar asked Dec 20 '22 06:12

sa125


1 Answers

This answer has been updated with improved information on routing and an example in keeping with the question.

There are now three examples:- simple, improved and elegant.

1.

Simple solution is to use Jinja's Block content function in your base.html template's head section.

base.html:

<meta name="description" content="{% block description %}{% endblock %}" />
<meta name="keywords" content="{% block keywords %}{% endblock %}" />
<meta name="author" content="{% block author %}{% endblock %}" />
<meta name="foo" content="{% block bar %}{% endblock %}" />

Then from any child.html you can set the block content, like so:

{% block description %}description from your child page.{% endblock %}
{% block keywords %}website, blog, coding{% endblock %}
{% block author %} {{ author.fullname }} {% endblock %}
{% block bar %}foo bar content{% endblock %}

Updated...

2.

View.py

@app.route('/some-route/<slug>')
def action(): 
   foo='bar'
   ping='pong'
   return render_template('child.html', foo, ping)

Not sure why your meta_data is a decorator here, so changed my example.

base.html

<html>
<head>
    {% block metadata %}{% endblock %}
</head>
...

child.html

{% extends "base.html" %}
{% block metadata %}
   <meta name="meta_tags" content="{{ foo }}{{ping}}" />
   <meta name="description" content="{{ foo }}" />
   <meta name="keywords" content="{{ ping }}" />
{% endblock %}

3.

Elegant & concise alternative:

View.py

@app.route('/some-route/<slug>')
def action():
   metadata = {'keywords': 'foo', 'description': 'bar'}
   return render_template('child.html', metadata=metadata)

N.B: base.html remains the same.

child.html

{% extends "base.html" %}
    {% block metadata %}
    <ul>
    {% for key, item in metadata.items() %}
       <meta name="{{ key }}" content="{{ item }}" />
    {% endfor %}
    </ul>
{% endblock %}

More information can be found on Jinja templates, using Block content and template inheritance at: http://jinja.pocoo.org/docs/dev/templates/#template-inheritance

like image 191
4 revs, 2 users 98% Avatar answered Mar 30 '23 04:03

4 revs, 2 users 98%