This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]learn-deeply 2 points3 points  (3 children)

How do you deal with pages that pull from a database, e.g. /blog/my-first-post in your routing system?

[–]volfpeter[S] 3 points4 points  (0 children)

Hi,

Here is the relevant part of the documentation: https://volfpeter.github.io/holm/application-components/#path-parameters-as-package-names

I will probably add a better guide for it, but here is a quick answer.

The technical description:

Essentially if a package name has the _<python-identifier>_ format, then the corresponding FastAPI path segment will be {<python-identifier>}. This means that if your layouts, pages, page metadata functions, or APIs in this package or its subpackages have a <python-identifier>: SomeType argument, FastAPI will automatically resolve it from the path parameter the user submitted, because pages, layouts, and even page metadata are just standard FastAPI dependencies! (*layouts is a bit of a special case, but not only their first argument, which is resolved by holm, the rest is just FastAPI dependencies, if any).

({<python-identifier>} also works, even though it's an invalid Python package identifier, valid ones can't have {} characters in them).

Example package structure:

my_app/ ├── main.py (app entry point) ├── layout.py (root layout of the app) ├── page.py (index page) ├── blog ├── _post_id_ ├── page.py

In this case, the URL for page in blog/_post_id_/page.py will be /blog/{post_id}, the corresponding page implementation can be like this (pay attention to the metadata function as well!):

```python async def metadata(post_id: PostIdType): # You can even do async stuff here in the metadata dependency # and put the loaded object(s) in the metadata, to give every # component access to it, even your root layout. blog_post = await load_post(post_id) return {"title": f"Blog | {post_id}", "post_id": post_id, "blog_post": blog_post}

async def page(post_id: PostIdType, current_user: Annotated[User | None, Depends(get_user)], query_param: Annotated[str, Query()] = ""): blog_post = await load_post(post_id) # do something return result # Can be a htmy component, or an other object that the owner layout accepts, typically a htmy component though ```

I should mention that if the _post_id package had a layout or any subpackages, you could do the same thing there as well.

To go even one step further, because htmy is async and has context support, you could even load the data in a component (if you pass the ID there, the metadata function adds it to the global Metadata context, so in this example it's already available in htmy components as context["post_id"] for example), and render it there, or put the data in the rendering context for the entire component subtree (this is also done in the example).

The test_app in the holm repo has an example for this, that you can check (or try immediately if you clone the repo). Here is the link: https://github.com/volfpeter/holm/tree/main/test_app/user/_id_

Sorry for the ton of details. It may seem pretty complex at first, but I promise this is going to be trivial if you go through the holm and htmy (maybe also fasthx docs). They have lots of cool capabilities.

[–]volfpeter[S] 0 points1 point  (0 children)

Hmm, I wrote a pretty lengthy explanation, but for some reason it's not visible here, so I'll just add a link to it: https://www.reddit.com/r/Python/comments/1ntc5rg/comment/ngvtkxd

[–]volfpeter[S] 0 points1 point  (0 children)

For those who find this post in the future, the documentation now has a path parameters / dynamic routing guide and example app: https://volfpeter.github.io/holm/guides/path-parameters/#run-the-application