How to submit HTML form <input> value using FastAPI and Jinja2 Templates?

Leonardo Lopes

I am facing the following issue while trying to pass a value from an HTML form <input> element to the form's action attribute and send it to the FastAPI server.

This is how the Jinja2 (HTML) template is loaded:

# Test TEMPLATES
@app.get("/test",response_class=HTMLResponse)
async def read_item(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

My HTML form:

<form action="/disableSubCategory/{{subCatName}}">
    <label for="subCatName">SubCategory:</label><br>
    <input type="text" id="subCatName" name="subCatName" value=""><br>
    <input type="submit" value="Disable">
</form>

My FastAPI endpoint to be called in the form action:

# Disable SubCategory
@app.get("/disableSubCategory/{subCatName}")
async def deactivateSubCategory(subCatName: str):
    disableSubCategory(subCatName)
    return {"message": "SubCategory [" + subCatName + "] Disabled"}

The error I get:

"GET /disableSubCategory/?subCatName=Barber HTTP/1.1" 404 Not Found

What I am trying to achieve is the following FastAPI call:

/disableSubCategory/{subCatName} ==> "/disableSubCategory/Barber"

Anyone who could help me understand what I am doing wrong?

Thanks. Leo

Chris

Option 1

You can have the category name defined as Form parameter in the backend, and submit a POST request from the frontend using an HTML <form>, as described in Method 1 of this answer.

app.py

from fastapi import FastAPI, Form, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory='templates')

@app.post('/disable')
def disable_cat(cat_name: str = Form(...)):
    return f'{cat_name} category has been disabled.'

@app.get('/', response_class=HTMLResponse)
def main(request: Request):
    return templates.TemplateResponse('index.html', {'request': request})

templates/index.html

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
   </head>
   <body>
      <h1>Disable a category</h1>
      <form method="post" action="/disable">
         <label for="cat_name">Enter a category name to disable:</label><br>
         <input type="text" id="cat_name" name="cat_name">
         <input class="submit" type="submit" value="Submit">
      </form>
   </body>
</html>

Option 2

You can have the category name declared as query parameter in your endpoint, and in the frontend use a similar approach to the one demonstrated in your question to convert the value form the form <input> element into a query parameter, and then add it to the query string of the URL (in the action attribute).

Note that the below uses a GET request in contrast to the above (in this case, you need to use @app.get() in the backend and <form method="get" ... in the frontend, which is the default method anyway). Beware that most browsers cache GET requests (i.e., saved in browser's history), thus making them less secure compared to POST, as the data sent are part of the URL and visible to anyone who has access to the device. Thus, GET method should not be used when sending passwords or other sensitive information.

app.py

from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory='templates')

@app.get('/disable')
def disable_cat(cat_name: str):
    return f'{cat_name} category has been disabled.'

@app.get('/', response_class=HTMLResponse)
def main(request: Request):
    return templates.TemplateResponse('index.html', {'request': request})

templates/index.html

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
   </head>
   <body>
      <h1>Disable a category</h1>
      <form method="get" id="myForm" action='/disable{{ cat_name }}'>
         <label for="cat_name">Enter a category name to disable:</label><br>
         <input type="text" id="cat_name" name="cat_name">
         <input class="submit" type="submit" value="Submit">
      </form>
   </body>
</html>

If you instead would like to use a POST request—which is a little safer than GET, as the parameters are not stored in the browser's history, and which makes more sense when updating content/state on the server, compared to GET that should be used when requesting (not modifying) data—you can define the FastAPI endpoint with @app.post('/disable') and replace the above template with the below (similar to Method 2 of this answer):

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <script>
         document.addEventListener('DOMContentLoaded', (event) => {
            document.getElementById("myForm").addEventListener("submit", function (e) {
               var myForm = document.getElementById('myForm');
               var qs = new URLSearchParams(new FormData(myForm)).toString();
               myForm.action = '/disable?' + qs;
            });
         });
      </script>
   </head>
   <body>
      <h1>Disable a category</h1>
      <form method="post" id="myForm">
         <label for="cat_name">Enter a category name to disable:</label><br>
         <input type="text" id="cat_name" name="cat_name">
         <input class="submit" type="submit" value="Submit">
      </form>
   </body>
</html>

Option 3

You can still have it defined as path parameter, and use JavaScript in the frontend to modify the action attribute of the <form>, by passing the value of the form <input> element as path parameter to the URL, similar to what has been described earlier.

app.py

from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory='templates')

@app.post('/disable/{name}')
def disable_cat(name: str):
    return f'{name} category has been disabled.'

@app.get('/', response_class=HTMLResponse)
def main(request: Request):
    return templates.TemplateResponse('index.html', {'request': request})

templates/index.html

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <script>
         document.addEventListener('DOMContentLoaded', (event) => {
            document.getElementById("myForm").addEventListener("submit", function (e) {
               var myForm = document.getElementById('myForm');
               var catName = document.getElementById('catName').value;
               myForm.action = '/disable/' + catName;
            });
         });
      </script>
   </head>
   <body>
      <h1>Disable a category</h1>
      <form method="post" id="myForm">
         <label for="catName">Enter a category name to disable:</label><br>
         <input type="text" id="catName" name="catName">
         <input class="submit" type="submit" value="Submit">
      </form>
   </body>
</html>

Option 4

A variation of Option 3, using Fetch API, a JavaScript interface/library, to make an asynchronous HTTP request, in order to prevent the page from reloading/redirecting when submitting the HTML <form>, similar to this answer, as well as this answer and this answer.

app.py

from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory='templates')

@app.post('/disable/{name}')
def disable_cat(name: str):
    return f'{name} category has been disabled.'

@app.get('/', response_class=HTMLResponse)
def main(request: Request):
    return templates.TemplateResponse('index.html', {'request': request})

templates/index.html

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <script>
         document.addEventListener('DOMContentLoaded', (event) => {
            document.getElementById("myForm").addEventListener("submit", function (e) {
               e.preventDefault() // Cancel the default action
               var catName = document.getElementById('catName').value;
               fetch('/disable/' + catName, {
                     method: 'POST',
                  })
                  .then(resp => resp.text()) // or, resp.json(), etc.
                  .then(data => {
                     document.getElementById("response").innerHTML = data;
                  })
                  .catch(error => {
                     console.error(error);
                  });
            });
         });
      </script>
   </head>
   <body>
      <h1>Disable a category</h1>
      <form id="myForm">
         <label for="catName">Enter a category name to disable:</label><br>
         <input type="text" id="catName" name="catName">
         <input class="submit" type="submit" value="Submit">
      </form>
      <div id="response"></div>
   </body>
</html>

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How do you display markdown value using jinja2?

Submit form in MVC using HTML

Submit HTML Form using JavaScript

store html checkbox value into list using flask, jinja2

Scrapy, how to change value in input form, submit and then scrape page

How to show html form with submit button and hidden input fields in flutter

Populate a form using Flask / Jinja2 template. Input text fields are truncating data

HTML to Jinja2 how to attribute classes to form variables according to previous style

change input value before submit form using jQuery

Using Div to submit value for Form

How to add nested groupby using Jinja2 templates

How to autoreload Jinja2 templates using nginx, uswgi and flask?

How do I turn a form input type="text" into a HREF that sits behind a submit button, using HTML's 5 download attribute?

How to looping Flask Jinja2 form input..?

Is there a way to delete a row from an HTML table with user input using Flask (jinja2)?

How to integrate HTML data tag in jinja2 form submit?

How Would I Style A Contact Form With Jinja2 and HTML

How to format Python lists as an HTML list using Jinja2?

How to change an input value from JavaScript before submit a form

How to disable submit button if the form input has the same value - jQuery?

How to add additional input with value in modal before form submit in laravel

jinja2 fastapi, output dict to html not showing results

How to change, using React, the value of a form input after clicking the submit button

How can I submit form using javascript dom manipulation with input value

How to display uploaded image in HTML page using FastAPI & Jinja2?

How to display a bytes type image in HTML/Jinja2 template using FastAPI?

How to disable html form submit button if the input values are the same

How to iterate over a dictionary in Jinja2 using FastAPI?

How to upload a csv file using Jinja2 Templates and FastAPI , and return it after modifications?