I am moving my blog over from Jekyll to Flask. In my Jekyll blog I use Liquid includes to process overhead heavy items like youtube videos and images and to ensure uniformity so that they can all be updated in the same place if there's a style or code change to the site.
In Flask is there a way to have the Jinja2 template process Liquid variables in the body of the blog article when it's passed to render_template()?
Example:
#route('/article')
def article():
blog_body = "<h1>My Video</h1>{% include '_media.html' type='youtube' id='a2343lj' %}"
return render_template('home.html.j2', content = blog_body)
And then in home.html.j2:
{% block page_content %}
{{ content }}
{% endblock %}
When testing, the template renders the literal string and does not process the include in the variable. Is there any way to get the Jinja template to render the Liquid syntax in the variable passed to it?
While there does not appear to be any way to render a template string using Jinja2 syntax, there is a workaround. At the time the variable is set, you can process it using render_template_string from Flask.
Example:
from flask import render_template, render_template_string
#route('/article')
def article():
blog_body = render_template_string("<h1>My Video</h1>{% include '_media.html' type='youtube' id='a2343lj' %}")
return render_template('home.html.j2', content = blog_body)
Then at least the variable will be rendered at the time it is set, even if not whenever the template is rendered.
Related
This is moreso a question about pyvis graphs, but also involves a django server running with a sqlite3 backend. One of my views needs to produce an interactive pyvis graph and display it in the clients browser. I can do this without the django app with the following code:
from pyvis.network import Network
network = Network()
network.show('map.html')
As you can see with this method, pyvis creates an html file and save it to disk first. nework.show() simply opens the file in the browser. Because I will be running this on a django webapp, I would rather create the graph's html without saving it to disk, then just return it as a string in the HttpResponse for the view. Is it possible to do this, or is there another way that is more appropriate?
One way to do that is to save the pyvis graph into a file within the templates directory of Django. Instead of using network.show(), use network.save_graph(path_to_templates_dir/some_pyvis_file.html) and then include that file inside the template where you want to show the results using the Django tags {% include ‘pvis_graph_file.html’ %}
views.py
from pyvis.network import Network
from django.conf import settings
network = Network()
...
network.save_graph(str(settings.BASE_DIR)+'app/templates/pvis_graph_file.html')
templates/showReport.html
{% extends 'base.html' %}
{% block body %}
Content of Report with pyVis Graphs
{% include 'pvis_graph_file.html' %}
{% endblock %}
I am looking to make macros available inside of the articles for my flask blog. When the body of my blog changes I run the following code to render the body into HTML:
target.body_html = bleach.linkify(bleach.clean(render_template_string(value),tags=allowed_tags, attributes=allowed_attr, strip=True))
render_template_string(value) is the part I'm concerned about. To use a macro inside of the template string (value), every single string has to include the following in order for me to use the macros from this file in the article body:
{% import "includes/macros.html.j2" as macros %}
This would not be reasonable to ensure that writers have access to the macros that I write in all of their articles. Is there any way to pass that argument via the render_template_string() function so that it doesn't have to be defined in every string? Or to otherwise create a template that the string is rendered inside of? Something like the following:
render_template_string(string,macros=function_to_import_macros("includes/macros.html.j2"))
While there does not appear to be a solution to pass an entire macros template as context, get_template_attribute does appear to allow you to pass individual macros one at a time. Example:
includes/macros.html.j2:
{% macro hello() %}Hello!{% endmacro %}
{% macro hello_with_name(name) %}Hello, {{ name }}!{% endmacro %}
Template rendering code:
hello = get_template_attribute("includes/macros.html.j2","hello")
hello_with_name = get_template_attribute("includes/macros.html.j2","hello_with_name")
return render_template("index.html", hello=hello,hello_with_name=hello_with_name)
index.html:
{{ hello() }}
{{ hello_with_name("Bob") }}
This solution will allow for adding individual macros to the context while rendering a template or template_string and can even be added to the global context via this method. If anyone knows how to add an entire template full of macros, that'd rock, but this allows the basic needed functionality.
So I have been working with twig now, and I use a function manner to render all of my html. My question is, is there a way to render the blocks (with functions) first, and then the {% extends X %} afterwards?
example:
{% extends 'base.html.twig' %}
{% block body %}
{{ resource('script', 'google.com') }}
{% endblock %}
I would want the resource function to trigger, before the file is extended, in some way.
Reason why:
In the base I define another function which loads a head with a base configuration, it also gives easy options to load certain libraries such as bootstrap etc. But I want the user able to later, externally in a body add more resources and make them pop up in the head instead of in the body. I can give more code if needed but I think this will suffice since this is more a twig question than a php question.
The Grav's documentation clearly describes how a whole page or a folder could be hidden from unregistered users. It also describes how a whole page could be seen only by particular user groups.
But what about pieces of a page, let's say, some links or a private info I want to show on some conditions?
Ok, for registered users I found a snippet at Login plugin docs:
{% if grav.user.authenticated %}
content for registered users goes here
{% endif %}
But going wider - how can I show/hide pieces of a particular page depending on some custom logic in PHP code, i.e. not necessarily user related?
I'm thinking about a twig/shortcode plugin, something like:
{% if some.custom.condition.or.PHP.function %}
hidden content goes here
{% endif %}
or
[hidden_if_something] hidden content goes here [/hidden_if_something]
But not sure how exactly this should be implemented. So working examples would be appreciated. Thanks.
There is a recipe in the Grav documentation here. This provides an example of how to render the output of a PHP code result in a twig template.
In the example they create a plugin, and implement a twig extension providing access to a php function. They can then simply call that php function like in a twig template.
{{ example() }}
Following that example, you can implement whatever logic you would like in php, and call the function in a twig if statement.
{% if example() == true %}
your conditional output
{% endif %
We are using Twig as our templating engine but I'm stuck with a problem of the rendering order now. See - https://straightupcraft.com/articles/twig-processing-order
We are using amp for our new site and with amp and web components in general it is necessary to import the components (once) to use them. So the idea was to create a Twig Extension to accomplish exactly this. Everytime a component is used it is called via this twig function call. The function is checking the component, adding it to a stack and you can use it from now on. The stack then is transformed into a list of imports for the head of the page.
The problem here is Twigs top to bottom rendering. When I call said function in a partial or a template the rendering of "layout.twig" already took place and all function calls below/after are not affecting the stack.
Is there an option to change the rendering to inside out, so that the rendering is first using the lowest partial and "bubbles" up to templates and finally layout without them rendering before?
Another way to get the values in layout would nice as well.
Desired behavior:
Layout.twig
{{ getAllComponents() }}
{# should output component1 and component2 #}
{% block content %}
Page.twig
{% extends Layout.twig %}
{{ addComponent('component1') }}
{% include partials.twig %}
<component1>...</component1>
partials.twig
{{ addComponent('component2') }}
<component2>...</component2>
Actual behavior:
Layout.twig
{{ getAllComponents() }}
{# is empty #}
There is no option to change this behavior. However you can use a trick to archive this:
Render your content to a variable before you call getAllComponents()
layout.twig
{% set mainContent %}
{% block content %}{% endblock %}
{% endset %}
{{ getAllComponents() }}
{{ mainContent }}
There actually is a magical solution to this problem -- some genius wrote this Deferred Twig Extension which lets you run some code (output a variable, call a function, etc) in a block near the top of your layout, but wait until the rest of the twig templates have parsed before executing them. There's an example on that github page showing how you can achieve this.
As far as I know, no you cannot switch the rendering of a TWIG template.
However, I would recommend possibly looking at the {% embed %} or {{ render }} tags.
Embed allows specific TWIG files to be placed within others with variables, so you could pass each component into their relevant partials.twig file.
Render allows the use of embedding a separate controller action, so you create a ControllerAction that took in a component variable and renders its own TWIG file.
Documentation on Embed: https://twig.sensiolabs.org/doc/2.x/tags/embed.html
Documentation containing Render: https://twig.sensiolabs.org/doc/2.x/api.html