When using HTMX framework with Python Flask, you have to be able to:
serve a request as a HTML fragment if it's done by HTMX (via AJAX)
server a request as a full page if it's done by the user (e.g. entered directly in the browser URL bar)
See Single-page-application with fixed header/footer with HTMX, with browsing URL history or Allow Manual Page Reloading for more details.
How to do this with the Flask template system?
from flask import Flask, render_template, request
app = Flask("")
@app.route('/pages/<path>')
def main(path):
htmx_request = request.headers.get('HX-Request') is not None
return render_template(path + '.html', fullpage=not htmx_request)
app.run()
What's the standard way to output a full page (based on a parent template pagelayout.html):
{% extends "pagelayout.html" %}
{% block container %}
<button>Click me</button>
{% endblock %}
if fullpage is True, and just a HTML fragment:
<button>Click me</button>
if it is False?
This solution based on that we can use a dynamic variable when extending a base template. So depending on the type or the request, we use the full base template or a minimal base template that returns only our fragment's content.
Lets call our base template for fragments base-fragments.html:
{% block container %}
{% endblock %}
It's just returns the main block's content, nothing else. At the view function we have a new template variable baselayout, that contains the name of the base template depending on the request's type (originating from HTMX or not):
@app.route('/pages/<path>')
def main(path):
htmx_request = request.headers.get('HX-Request') is not None
baselayout = 'base-fragments.html' if htmx_request else 'pagelayout.html'
return render_template(path + '.html', baselayout=baselayout)
And in the page template, we use this baselayout variable at the extends:
{% extends baselayout %}
{% block container %}
<button>Click me</button>
{% endblock %}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With