Static restaurant website with LibreOffice and Python
4 min read

Static restaurant website with LibreOffice and Python

How I built a restaurant website using basic Python and LibreOffice calc as a backend
Static restaurant website with LibreOffice and Python

I was recently asked by a friend of mine to have a look at the website for his restaurant. The previous supplier programmed a PHP application from scratch for his website and it wasn't working well. While it was doing it's job, it was very hard to update things like the Menu or other text information.

The setup was rather simple so I asked my friend if it was ok for me to redesign and update the whole thing.

I had two things I wanted to keep in my mind:

  • The website shouldn't take too much time to create (lazy as possible) because I didn't want the project to end up costing me way too much in time
  • There should be a very simple and fast way of updating the menu, prices and other text fields
  • ... and I love food so it was my duty to do a restaurant website lol

The second point is very important because when dealing with restaurant websites I found it common that the owner expects free updates after the initial contract.

The idea

There is a Python library called pystache with which I work almost daily. It allows someone to define templates directly inside the page html like this and then access it in Python:

Template in {{ }} is accessible in Python thanks to Pystache

It is similar to Jinja2 with less features but enough of them to do the job. What you then do is create a HTML template in Python that should be inside of the {{content-nudel}}:

HTML Template written as a Python string

And the final step is then to use Pystache to render the Python HTML template inside the HTML page where you want it to end up in. As you may have noticed, the Python HTML template has also fields that can be adressed in Pystache (Menu and Price) in this case.

Which means:

  • Pystache loads the page-menu.html
  • Pystache finds the {{content-nudel}} and knows
  • In Python you map the {{content-nudel}} to the menu_entry_template
  • In Pystache you replace the Menu and Price fields from menu_entry_template
  • In Pystache you finally render page-menu.html with all the Price and Menu data

This sounds like a lot but the code is 10ish lines long:

To create the whole website, you then iterate a whole folder with html_templates containing double brackets {{replace_me}}. And you have a basic static website.

How the website looks once rendered

Now we have the View / Controller part of the MVC pattern we need a way to model our data. In this case we don't need fancy stuff but just a catalog of menu and prices, and some custom text. We need to get and parse the data from somewhere. I obviously don't want to write my own data handling and data storage component since it would take too much time and this is a solved problem. Every month there is a new static CMS!


I noticed my friend is using LibreOffice and I was surprised as to why not Excel? After some good cold german beers he explained to me that it was easy to use and he doesn't have to remember a login or to click on popups. Fun times.

So I'd thought why not use a tool he already uses to get the data for the website since he already uses it to order the hardware menu pages that stand on the table.

LibreOffice Calc sheet with multiple pages

Python has a very cool library called pyexcel-ods3 that makes it easy to read .ods (aka LibreOffice Excel pendant) files and parse them.

The interface couldn't be easier:

# get the data
data = get_data("menu.ods")
# get a page from the document
# header 
# content

And now you have the data to fill in the templates. The blog is then complete. Whenever an update is necessary my friend changes his LibreOffice Calc document, sends me the update and I pass it to the automated build pipeline. Other pages are also filled using this process using LibreOffice Writer documents and XHTML exporting.

The website is very fast and except Google Analytics there is no Javascript at all.


It would have made more sense to use a Google Sheet for the data exchange and I tried this option. The only problem is that it introduces more friction into the process for my friend. He either didn't find the Google sheet or couldn't work with it very well. Some things that are natural for us devs are not essentially natural for non-devs and this is why I think most of the work needs to be done at the interface.

LibreOffice Calc was in this case the sweet spot for exchangeability. All the rest is glue code and automation.

So yeah, the website is live for a while now and serving 40k visits per month without a single hitch. This project was done in 1h50 minutes and is running on a 3€/month server.