Tags
Out of the box Starlette does not support url_for with query params. When trying to use url_for with query params it throws the following error.
starlette.routing.NoMatchFound: No route exists for name "infinite" and params "page"
In my searching for this I found starlette issue #560 quite helpful, but not complete, as it did not work for me.
import jinja2 if hasattr(jinja2, "pass_context"): pass_context = jinja2.pass_context else: pass_context = jinja2.contextfunction @pass_context def url_for_query(context: dict, name: str, **params: dict) -> str: request = context["request"] url = str(request.url_for(name)) if params == {}: return url from urllib.parse import parse_qs, urlencode, urlparse, urlunparse # Parse the URL parsed_url = urlparse(url) # Parse the query parameters query_params = parse_qs(parsed_url.query) # Update the query parameters with the new ones query_params.update(params) # Rebuild the query string updated_query_string = urlencode(query_params, doseq=True) # Rebuild the URL with the updated query string updated_url = urlunparse( ( parsed_url.scheme, parsed_url.netloc, parsed_url.path, parsed_url.params, updated_query_string, parsed_url.fragment, ) ) if os.environ.get("ENV") in ["dev", "qa", "prod"]: updated_url = updated_url.replace("http", "https", 1) return updated_url def get_templates(): templates = Jinja2Templates(directory="templates") templates.env.globals["url_for"] = url_for_query return templates
"https"
If you want url_for to work in production you need some way to convert http
to https. Here is how I make it work, for local development I export ENV=local
then for each environment that I am running on a server I include
it in the list and update ENV
appropriately.
if os.environ.get("ENV") in ["dev", "qa", "prod"]: updated_url = updated_url.replace("http", "https", 1)
The route might look something like this.
@infinite_router.get("/") async def home(request: Request, page: int = 1, n: int = 10): ...
To access the home route using url_for in a jinja template you can use the
following, once you have applied the url_for_query
function as your default
url_for
<a href="{{ url_for('home', page=1) }}">Home</a>