Downloading files by pressing st.form_submit_button

Hi @konshinmitya, welcome to the forum! :wave: :partying_face:

Your post looks like a duplicate of Automatic Download / Select and Download File with Single Button Click - #4 by snehankekre

It looks like you’re trying to:

  1. open an existing .docx file from disk,
  2. ask the user to manipulate the contents of the file in a form, and
  3. expect the user to click the form submit button to download another .docx file containing the edited content.

Here’s how you can do that. I assume there exists a Test.docx file containing “Hello world”, and use python-docx to work with .docx files:

import base64
from io import BytesIO

import docx
import streamlit.components.v1 as components
from docx import Document
import streamlit as st

def download_button(object_to_download, download_filename):
    """
    Generates a link to download the given object_to_download.
    Params:
    ------
    object_to_download:  The object to be downloaded.
    download_filename (str): filename and extension of file. e.g. mydata.docx,
    Returns:
    -------
    (str): the anchor tag to download object_to_download
    """
    try:
        # some strings <-> bytes conversions necessary here
        b64 = base64.b64encode(object_to_download.encode()).decode()

    except AttributeError as e:
        b64 = base64.b64encode(object_to_download).decode()

    dl_link = f"""
    <html>
    <head>
    <title>Start Auto Download file</title>
    <script src="http://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script>
    $('<a href="data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64,{b64}" download="{download_filename}">')[0].click()
    </script>
    </head>
    </html>
    """
    return dl_link

def load_sample_doc(path):
    # doc = Document(path)
    # return doc
    # You can alternatively use the above to avoid file handling
    f = open(path, "rb")
    document = Document(f)
    f.close()
    return document

def download_docx():
    edited_doc = doc.add_paragraph(st.session_state.paragraph)
    buff = BytesIO()  # create a buffer
    doc.save(buff)  # write the docx to the buffer
    components.html(
        download_button(buff.getvalue(), st.session_state.filename),
        height=0,
    )

doc = load_sample_doc(path="Test.docx")

with st.form("my_form", clear_on_submit=False):
    st.text_area("Add paragraph", key="paragraph")
    st.text_input("Filename (must include .docx)", key="filename")
    submit = st.form_submit_button("Download docx", on_click=download_docx)

auto-download-docx

3 Likes