I’ve recently been using the htmx (https://htmx.org/) javascript library to make some simple Flask web applications I have made a bit more dynamic.
The page is very simple, but contains a big table of data in the center. It has a form at the top of the page that allows you to write simple queries for data in the page. When a user types in a SQL Query, the htmx library allows me to reload the table, without fully reloading the page:

What I wanted was:
- if a user typed a SQL query it would be saved in the query string in the URL bar
- if a user sorted the columns the query would be saved into the query string in the URL bar also
This would allow a user to bookmark or copy the url, and then send it to some other user, and they could get the same data.
The htmx library provides the ability for the server-side to send back a URL to be pushed into the browser: https://htmx.org/reference/#response_headers
The way this works, is that you set the HX-Push
response header, and the URL in that header will be pushed to the browser’s history+url bar.
One complication was that the sorting of the table is done client-side, but the querying is done server-side. This means that the query parameters get all mixed together when the request comes to the backend, so what I needed to do on the Flask side is split up the request.referrer
(the URL the request came from) as well as the request.args
(the query params of the htmx partial request).
Enough talk, lets see the code:
def server_table(db_session):
# these are the parameters I care about in the htmx triggered request
sqlquery_query = request.args.get('sqlquery')
showdecom_query = request.args.get('showdecom')
if request.referrer: # the referrer is the current top-level URL
# Build a new URL to push to history for htmx
referrer_url = list(urllib.parse.urlparse(request.referrer))
# parse the query_string_list (qsl)
query_dict = dict(urllib.parse.parse_qsl(referrer_url[4]))
# Remove the items from the referrer that should only come from the htmx triggered request:
query_dict.pop('showdecom', None)
query_dict.pop('sqlquery', None)
filtered_args = filter(lambda item: bool(item[1]), request.args.items()) # we only want query items that have a value
query_dict.update(filtered_args) # add them to the to the new query we are building
referrer_url[4] = urllib.parse.urlencode(query_dict)
new_history_url = urllib.parse.urlunparse(referrer_url)
else:
new_history_url = None
response = flask.Response(generate_server_table(db_session))
if new_history_url: # if we built a new URL, send it in the response header
response.headers["HX-Push"] = new_history_url
return response