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>
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
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.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)
@app.get('/{pk}')
def user_profile(request: Request, pk: int):
return templates.TemplateResponse("profile.html", {"request": request, "pk": pk})
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('/{pk}')
def user_profile(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}'
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!")
The request.url_for()
function now returns a starlette.datastructures.URL
object. Hence, you could simply use include query parameters as follows:
redirect_url = request.url_for('user_profile', pk=pk).include_query_params(message="Success!")