I’m doing a feature where the user on their profile page makes changes (not related to the user model). Everything is implemented through static HTML
templates. I need the user to click on the button and return to the same page (i.e., their profile page) after processing the request.
Html template
<td><a href="{{ url_for('decline_event_invite', pk=invite.id) }}" class="btn blue lighten-2">Accept</a></td>
endpoints.py
@router.get('/invite/{pk}/decline') async def decline_event_invite( request: Request, pk: int, user_id: str = Depends(get_current_user), service: InviteService = Depends(), ): await service.invite_decline(pk) ... --> here I want redirect to user profile page return RedirectResponse('DYNAMIC URL WITH ARGS')
profile.py
@router.get('/{pk}') async def user_profile( request: Request, pk: int, service: UserService = Depends() ): user = await service.get_user_info(pk) events_invites = await service.get_user_events_invite_list(pk) return templates.TemplateResponse( 'profile.html', context= { 'request': request, 'user': user, 'events_invites': events_invites, } )
But I can’t find anywhere how to do a redirect similar to the logic that applies to templates. For example:
<a href="{{ url_for('user_profile', pk=pk) }}">Sender</a>
Advertisement
Answer
You can use url_for()
function and pass the (**kwargs
) path parameters.
import uvicorn from fastapi import FastAPI, Request from fastapi.templating import Jinja2Templates from fastapi.responses import RedirectResponse import urllib from fastapi import APIRouter router = APIRouter() templates = Jinja2Templates(directory="templates") @router.get('/invite/{pk}/decline') def decline_event_invite(request: Request, pk: int): redirect_url = request.url_for('user_profile', **{ 'pk' : pk}) return RedirectResponse(redirect_url) @router.get('/{pk}') def user_profile(request: Request, pk: int): return templates.TemplateResponse("profile.html", {"request": request, "pk": pk}) if __name__ == "__main__": uvicorn.run(router, host='127.0.0.1', port=8000, debug=True)
To add query params
In case you had to pass query params as well, you could use the following code (make sure to import urllib
). Alternatively, you could use the CustomURLProcessor
, as described in this and this answer (which pretty much follows the same approach).
If the endpoint expected query params, for example:
@router.get('/invite/{pk}/decline') def decline_event_invite(request: Request, pk: int, message: str): pass
you could use:
redirect_url = request.url_for('user_profile', pk=pk) parsed = list(urllib.parse.urlparse(redirect_url)) parsed[4] = urllib.parse.urlencode({**{ 'message' : "Success!"}}) redirect_url = urllib.parse.urlunparse(parsed)
or even use:
message = 'Success!' redirect_url = request.url_for('user_profile', pk=pk) + f'?message={message}'
Update
Another solution would be to use Starlette’s starlette.datastructures.URL
, which now provides a method to include_query_params
. Example:
from starlette.datastructures import URL redirect_url = URL(request.url_for('user_profile', pk=pk)).include_query_params(message="Success!")