Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate full page or HTML fragment based on request header (HTMX)

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?

like image 389
Basj Avatar asked Nov 16 '25 03:11

Basj


1 Answers

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 %}
like image 71
Dauros Avatar answered Nov 17 '25 19:11

Dauros