question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[FEATURE] Combining Form() with Arbitrary dicts

See original GitHub issue

I just spent a lot of time trying to get this to work:

app.post("/post-form-here")
def process_this_form(form_data: Dict[str, str] = Form(...)):
    # this does not work
    pass

The documentation needs to be updated to make clear this will not work. At first it looks like you should be able to combine Form Data with Bodies of Arbitrary dicts. I could be wrong but I think there’s no way to do this in FastAPI. If you are using Form() you have to explicitly define every form field one by one no matter how many fields you have, like so:

app.post("/post-form-here")
def process_this_form(
    parameter_a: str = Form(...),
    parameter_b: str = Form(...),
    parameter_c: str = Form(...),
    parameter_d: str = Form(...),
    parameter_e: str = Form(...),
    parameter_f: str = Form(...),
    parameter_g: str = Form(...),
    parameter_h: str = Form(...),
    parameter_i: str = Form(...),
    parameter_j: str = Form(...),
    parameter_k: str = Form(...),
    parameter_l: str = Form(...),
    parameter_m: str = Form(...),
    parameter_n: str = Form(...),
    parameter_o: str = Form(...),
    parameter_p: str = Form(...),
    parameter_q: str = Form(...)):
    # this works
    pass

And you cannot have any arbitrary Form() fields either.

The solution I would like would be either to make this work like in Flask, where you have available request.form (a dict containing all x-www-form-urlencoded data.) Or else have the documentation explicitly state that you can’t combine these two concepts Form Data with Bodies of Arbitrary dicts, and there is just no way to do it in FastAPI.

In my case I have 27 fields that go into a NamedTuple which goes into a table. To put 27 Form() parameters into one Python function def is going to be the longest def I’ve ever written, but I’d rather do that than waste a weekend beating my head against a wall.

I understand it may not be possible with the current design to read request.form like in Flask but please save people frustration by stating this up front in the documentation for Form().

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

5reactions
nsidnevcommented, Jan 13, 2020

@tfishr Hi! I suppose that you are looking for request.form() method from the Starlette on which FastAPI is based. You can pass the Request object from Starlette as described here. This asynchronous method will return a dict-like object that can be used for your purposes:

from fastapi import FastAPI
from starlette.requests import Request

app = FastAPI()


@app.post("/my-form-endpoint")
async def my_endpoint(request: Request) -> dict:
    form_data = await request.form()
    # do something with form data
    return form_data  # just return passed data as json

Since the request.form() method is asynchronous, you cannot use it directly in your example with synchronous endpoint, but you can wrap receiving of your data from the form in a separate dependency and return either the data received from request.form() or the object that you create from this data:

from fastapi import FastAPI, Depends
from starlette.requests import Request

app = FastAPI()


async def parse_my_form(request: Request) -> dict:
    form_data = await request.form()
    return dict(form_data)


@app.post("/my-form-endpoint")
def my_endpoint(form_data: dict = Depends(parse_my_form)) -> dict:
    return form_data
1reaction
C0l0redcommented, Oct 28, 2020

Okay, I get this But how can I do that reverse? How can I unpack a dict or list or class of forms as parameters to a function I just discovered Fast API and the thought of defining every form attribute in every function parameter has been keeping me from moving from Flask. The way you can do…

class Person(BaseModel):
    name: str = Field("name")
    age: int = Field(18)

@app.route("/login")
def login(person: Person):
    return person

For Body, how can I do something similar with Form, Cookie, Query to make them reusable?

Nevermind, I just reread this and read dependencies I’m clear now, thanks

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to merge dictionaries of dictionaries? - Stack Overflow
A recursive merger function f to be used together with merge. Implementation. A function for merging two (non nested) dicts can be written...
Read more >
Python Nested Dictionary - Learn By Example
You can use dict() function along with the zip() function, to combine separate lists of keys and values obtained dynamically at runtime.
Read more >
Extra Models - FastAPI
Pydantic models have a .dict() method that returns a dict with the model's data. ... If we take a dict like user_dict and...
Read more >
Python Dict and File | Python Education - Google Developers
A for loop on a dictionary iterates over its keys by default. The keys will appear in an arbitrary order. The methods dict.keys()...
Read more >
6.2. Feature extraction — scikit-learn 1.2.0 documentation
The following dict could be such a window of features extracted around the ... vec = DictVectorizer() >>> pos_vectorized = vec.fit_transform(pos_window) ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found