The visits log¶
A how-to guide: record what is read, and let the framework’s readership pages show it back.
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from sextile import Page, PageRequest, PageRouter, Sextile, StateKey, notice_page, standard_pages
from sextile.middleware import record_visits
from sextile.visits import SqliteVisits, Visits
VISITS = StateKey[Visits]("visits")
router = PageRouter()
@router.page("11", name="news", title="Headlines")
async def news(request: PageRequest) -> Page:
return notice_page(request, "Nothing yet.")
@router.page("12", name="sport", title="Sport")
async def sport(request: PageRequest) -> Page:
return notice_page(request, "Rained off.")
@asynccontextmanager
async def lifespan(app: Sextile) -> AsyncIterator[None]:
with SqliteVisits.open(":memory:") as visits:
app.state[VISITS] = visits
yield
app = Sextile(
name="News",
pages=[*router, *standard_pages(recent="9", visits=VISITS)],
middleware=[record_visits(VISITS)],
lifespan=lifespan,
)
PAGES LATELY READ 9a 1 Headlines *11# just now 2 Sport *12# just now 1-2 select, 0 index
record_visits(VISITS) middleware notes every page built under a StateKey the
lifespan opens a SqliteVisits under; standard_pages(recent="9", visits=VISITS)
routes the framework’s own “looked at lately” page at 9, reading that same log.
popular= and callers= add the most-read page and the caller count the same
way. Each caller is an opaque token, so the count says how many and nothing about
who.
Middleware in general is Middleware, of which this is the
third worked use; logging every page is Log every page. Why record_visits
is handed the state key and why the log keeps its own file are in
Design decisions.