3

I have a variable set in one view in Fastapi and want to pass it to another one :

from fastapi import APIRouter, Request, Response
from fastapi.templating import Jinja2Templates

templates = Jinja2Templates(directory="templates")
router = APIRouter()

@router.get("/my-first-view")
async def function1(request: Request) -> Response:
    """Display the home page."""
    my_variable = value
    return templates.TemplateResponse(
        "home.jinja",
        context={
           "my_variable": my_variable
        },
    )

@router.get("/my-second-view")
async def function2(request: Request, my_variable: str) -> Response:
    """Display the variable processing page."""
    
    return templates.TemplateResponse(
        "page.jinja"
    )

Normally, this would come to send my_variable from home.jinja to page.jinja. Thus, in home.jinja I have the following :

...
<a href="{{url_for('function2', my_variable=my_variable)}}" title="connect">Connect</a>
...

But this is throwing me an error : "starlette.routing.NoMatchFound: No route exists for name \"function2\" and params \"my_variable\".\n". I did some researches but I haven't found something really helpful

What is the proper way to do it with Fastapi ? What am I missing ?

aaronted
  • 187
  • 1
  • 6
  • 20
  • use cookies/session so that each user carries their own variable. Otherwise you may show a variable from one user to another. – The Fool Nov 29 '22 at 08:32
  • 1
    Starlette's `url_for` does not support query arguments directly. You can instead add them directly after the `url_for` part: `{{ url_for(...) }}?my_variable={{ my_variable }}` (and [apply a filter for query param escaping if necessary](https://stackoverflow.com/questions/33450404/quote-plus-url-encode-filter-in-jinja2)). Also see [Chris' answer about url_for in Starlette for more details](https://stackoverflow.com/questions/71067363/send-query-params-from-jinja-template). – MatsLindh Nov 29 '22 at 11:06

1 Answers1

-1

Very little context information on this post, so I'll help out with fixes that change as little as possible.

First of all, to fix your code you need a place to save the changes that you've made. A variable that only exists in a function is deleted at the end of that function.

Now usually you'd give more information regarding your use case, and I'd give you the best choice and why. It could be to store data in a JSON file, or a Database, or an in memory object that would serve the purpose best.

Here there's no info so we'll just make a variable. Keep in mind that this variable will be reset every time you restart the shell. So if your API is not "always on" then this may no work.

from fastapi import APIRouter, Request, Response
from fastapi.templating import Jinja2Templates

VARIABLE = None
API_URL = "my_domain.com/api"

templates = Jinja2Templates(directory="templates")
router = APIRouter()

@router.get("/my-first-view")
async def function1(request: Request) -> Response:
    """Display the home page."""
    my_variable = value
    return templates.TemplateResponse(
        "home.jinja",
        context={
           "complete_url": f"{API_URL}/my-second-view?my_variable={VARIABLE}"
        },
    )

@router.get("/my-second-view")
async def function2(request: Request, my_variable: str) -> Response:
    """Display the variable processing page."""

    VARIABLE = my_variable
    
    return templates.TemplateResponse(
        "page.jinja"
    )

As far as the template goes, you haven't shared url_for, but I suppose it just creates the path. I'd just make home.jinja as follows.

<a href="{{ complete_url }}" title="connect">Connect</a>

Also I've replaced the url_for call with a simple f-string. Depending on what you pass in your VARIABLE you may need to encode it.

For an example of that, please look at the following thread: How to urlencode a querystring in Python?

scr
  • 853
  • 1
  • 2
  • 14
  • thank you for your response. Yes, I was trying to be a bit 'global' as a general use case here. I'll provide further details if needed? Regarding this line `complete_url: url_for('function2', my_variable=VARIABLE)` I'm having `complete_url` and `url_for` not defined – aaronted Nov 29 '22 at 06:28
  • I'll add a definition for those, but you have to give me the API hostname – scr Nov 29 '22 at 07:41
  • Okay, may I please know how it is relevant..? It is not an information I can really disclose yet. – aaronted Nov 29 '22 at 08:15
  • Fine I'll just put a placeholder in the code, make sure you change it in the real thing – scr Nov 29 '22 at 08:23
  • 1
    Using global variables is bad, especially if your handlers using the variable are used concurrently. This has race conditions. Don't do that! – The Fool Nov 29 '22 at 08:31
  • @TheFool, I get it thank you. I'm the one that kept the question a bit global for general use case as I was saying. I'll add further details. – aaronted Nov 29 '22 at 08:36
  • 2
    Even for a general use case, its broken. You can do that only if your code is runs in a single thread sequentially. – The Fool Nov 29 '22 at 08:37
  • Just for the record, @scr solution is doing what I intended to do in the initial wrapped up post. Just know that's not good practice and it's appropriate only in a specific case `You can do that only if your code is runs in a single thread sequentially.` as mentioned above. – aaronted Nov 29 '22 at 10:18
  • @aaronted can I get the green check ? – scr Nov 29 '22 at 11:00