2

How can I generate HTML containing images and text, using a template and css, in python?

There are few similar questions on stackoverflow (e.g.: Q1, Q2, Q3) but they offer solutions that (to me) seem overkill, like requiring servers (e.g. genshi).

Simple code using django would be as follows:

from django.template import Template, Context
from django.conf import settings
settings.configure() # We have to do this to use django templates standalone - see
# https://stackoverflow.com/questions/98135/how-do-i-use-django-templates-without-the-rest-of-django

# Our template. Could just as easily be stored in a separate file
template = """
<html>
<head>
<title>Template {{ title }}</title>
</head>
<body>
Body with {{ mystring }}.
</body>
</html>
"""

t = Template(template)
c = Context({"title": "title from code",
             "mystring":"string from code"})
print t.render(c)

(From here: Generating HTML documents in python)

This code produces an error, supposedly because I need to set up a backend:

Traceback (most recent call last):
  File "<input>", line 17, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/template/base.py", line 184, in __init__
    engine = Engine.get_default()
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/template/engine.py", line 81, in get_default
    "No DjangoTemplates backend is configured.")
django.core.exceptions.ImproperlyConfigured: No DjangoTemplates backend is configured.

Is there a simple way to have a template.html and style.css and a bunch of images, and use data in a python script to replace placeholders in the template.html without having to set up a server?

Community
  • 1
  • 1
joeDiHare
  • 619
  • 8
  • 19
  • 2
    The error is just telling you that you need to pass some template settings into `settings.configure()`. But why not use a standalone templating system like [Jinja2](http://jinja.pocoo.org/)? – Daniel Roseman Oct 06 '16 at 11:42
  • Just for your information: genshi does **not** "require a server". – bruno desthuilliers Oct 06 '16 at 11:54
  • @brunodesthuilliers, could you articulate as to why genshi does not require a server? I am possibly a bit confused about this aspect and you could help me clarifying my question too. From this tutorial (https://genshi.edgewall.org/wiki/GenshiTutorial) it seems that by invoking "$ PYTHONPATH=. python geddit/controller.py geddit.db" a server is launched to display results on the browser. Thanks. – joeDiHare Oct 06 '16 at 13:34
  • @DanielRoseman - I am not sure which template settings I should be passing? settings.configure(DEBUG=True) produces the same error. Will look into Jinja2, but shouldn't this be doable with django already? – joeDiHare Oct 06 '16 at 13:46
  • https://docs.djangoproject.com/en/1.10/ref/settings/#std:setting-TEMPLATES – Daniel Roseman Oct 06 '16 at 13:48
  • But the point is that Jinja is already a standalone template system, which appears to be what you are asking for. Django is a web framework, which is both overkill and naturally harder to set up in the way you want. – Daniel Roseman Oct 06 '16 at 13:48
  • @joeDiHare this thing about cherrypy etc is just for the tutorial (posssibly since serving dynamic html is the most frequent use case for html templating). Genshi by itself _is_ a standalone template engine. – bruno desthuilliers Oct 06 '16 at 15:18

3 Answers3

1

I use code like this:

self.content = '''
    <html>
        <head>
            ''' + base_pyhtml.getAdmin ('documentation') + '''
            <style>
                ''' + base_pycss.getAll () + '''
                ''' + documentation_pycss.getAll () + '''
            </style>
        </head>
        <body>
            ''' + base_pyhtml.getFixed () + '''

            <div class="moving">
                <div class="documentation">

and

def getAll ():
    return '''
        * {
            margin: 0;
            padding: 0;
        }

        body {
            font-family: arial;
        }

        html {
            visibility: hidden;
        }

        h1 {
            margin-bottom: 30;
            padding: 10 1 10 1;
            text-align: center;
            color: ''' + logoGreen + ''';
            background-color: ''' + panoramaPink + ''';
            font-size: 110%;

For me it works fine in practice. This site was completely made with this trivial technique. What I like is that I can use the full power of Python in this way, rather than being restricted by or even learning special template syntax.

By using .pyhtml and .pycss extensions and configuring my editor, I get HTML and CSS syntax highlighting on this type of code as shown below:

enter image description here

Jacques de Hooge
  • 6,750
  • 2
  • 28
  • 45
1

There are quite a few python template engines - for a start you may want to have a look here : https://wiki.python.org/moin/Templating

As far as I'm concerned I'd use jinja2 but YMMV.

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
1

Thanks for your answers, they helped me coming up with something that works for me.

In the script below I am using jinja2 to render an html file ('index.html').

from jinja2 import Template, Environment, FileSystemLoader

# Render html file
env = Environment(loader=FileSystemLoader('templates'))
template = env.get_template('index.html')
output_from_parsed_template = template.render(no_users=len(users), do_stages=do_stages, users=users,                                                 message_counts=message_counts)

# to save the results
with open("OutputAnalysis.html", "w") as fh:
    fh.write(output_from_parsed_template) 

The html template is:

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- <link rel="stylesheet" type="text/css" href="styles.css"> -->
    <style type="text/css">
    #share-buttons img {
        width: 32px;
        padding: 5px;
        border: 0;
        box-shadow: 0;
        display: inline;
    }    
    body    {
        padding-left: 5px;
        padding-right: 5px;
        color: black;
        max-width: 450px;
        text-align: center; 
    }

    </style>
    <title>Your file 2016</title>
</head>
<body>
    <h1>This has {{ no_users }} users:</h1>
    <ul id="users">
    {% for user in users %}
        <li>{{user}}</li>
    {% endfor %}
    </ul>

    {# STAGE 1 #}
    {% if 1 in do_stages%}
    <h1>Something worth showing</h1>
    <p> 
        <img src="image.png" alt="caption" style="width:200px;height:200px;"> 
    </p>
    {% endif %}

    {# STAGE 2 #}
    {% if 2 in do_stages%}
    <h1>Other header</h1>
    <p> 
        {% for u in range(0,no_users) %}
        <p>{{users[u]}} sent {{message_counts[u]}} messages.</p>
        {% endfor %}
    </p>
    <p> 
    {% endif %}


    <div id="share-buttons">
        <!-- Twitter -->
    <a href="https://twitter.com/share?url=https://stefanocosentino.com" target="_blank">
        <img src="twitter_icon.png" alt="Twitter" />
    </a>

</body>
</html>

The html file has the <style> defined in the <head> and loads from the local folder "template".

joeDiHare
  • 619
  • 8
  • 19