DocsUnité 2 : données
Créer une application de notes avec Nexy, partie 9 : paginer les notes
La partie 9 montre les notes cinq à la fois, avec des liens vers les pages suivantes et précédentes, lues à partir du page de l'URL : /notes?page=2.
Avant de commencer : l'application de la partie 8.
Demander une page à la base de données
OFFSET saute les notes des pages précédentes, LIMIT en garde cinq. En demander un plus de cinq indique, gratuitement, si une page suivante existe :
from sqlmodel import Session, select from src.configs.db import enginefrom src.models.note_model import Note def all_notes() -> list[Note]: with Session(engine) as session: return list(session.exec(select(Note).order_by(Note.id))) def find(note_id: int) -> Note | None: with Session(engine) as session: return session.get(Note, note_id) def add_note(text: str) -> Note: note = Note(text=text) with Session(engine) as session: session.add(note) session.commit() session.refresh(note) return note def change_note(note_id: int, text: str) -> bool: with Session(engine) as session: note = session.get(Note, note_id) if note is None: return False note.text = text session.commit() return True def remove_note(note_id: int) -> bool: with Session(engine) as session: note = session.get(Note, note_id) if note is None: return False session.delete(note) session.commit() return True PAGE_SIZE = 5 def notes_page(number: int) -> tuple[list[Note], bool]: """One page of notes, oldest first, and whether a page comes after it.""" with Session(engine) as session: query = select(Note).order_by(Note.id).offset((number - 1) * PAGE_SIZE).limit(PAGE_SIZE + 1) found = list(session.exec(query)) return found[:PAGE_SIZE], len(found) > PAGE_SIZEfrom sqlmodel import Session, select from src.apps.notes.note_model import Notefrom src.configs.db import engine def all_notes() -> list[Note]: with Session(engine) as session: return list(session.exec(select(Note).order_by(Note.id))) def find(note_id: int) -> Note | None: with Session(engine) as session: return session.get(Note, note_id) def add_note(text: str) -> Note: note = Note(text=text) with Session(engine) as session: session.add(note) session.commit() session.refresh(note) return note def change_note(note_id: int, text: str) -> bool: with Session(engine) as session: note = session.get(Note, note_id) if note is None: return False note.text = text session.commit() return True def remove_note(note_id: int) -> bool: with Session(engine) as session: note = session.get(Note, note_id) if note is None: return False session.delete(note) session.commit() return True PAGE_SIZE = 5 def notes_page(number: int) -> tuple[list[Note], bool]: """One page of notes, oldest first, and whether a page comes after it.""" with Session(engine) as session: query = select(Note).order_by(Note.id).offset((number - 1) * PAGE_SIZE).limit(PAGE_SIZE + 1) found = list(session.exec(query)) return found[:PAGE_SIZE], len(found) > PAGE_SIZELire le numéro de page à partir de l'URL
Le page de la chaîne de requête est le texte envoyé par le visiteur : tout ce qui n'est pas un nombre positif revient à la première page, donc /notes?page=abc répond toujours.
from "@/components/NoteCard.nexy" import NoteCardfrom nexy import useSearchParamsfrom src.notes import notes_page params = useSearchParams()error = params.get("error", "")asked = params.get("page", "1")number = max(int(asked), 1) if asked.isdigit() else 1found = notes_page(number)notes = found[0]more = found[1]<section class="app-page"> <h1>Notes</h1> {% if error %} <p class="note-error" role="alert">{{ error | e }}</p> {% endif %} <form method="post" action="{{ __actions_path['create_note'] }}"> <input name="text" placeholder="A new note" maxlength="200" required> <button type="submit">Add</button> </form> {% for note in notes %} <NoteCard id="{{ note.id }}" text="{{ note.text }}" /> {% endfor %} <nav class="note-pages" aria-label="Pages of notes"> {% if number > 1 %}<a href="/notes?page={{ number - 1 }}" rel="prev">Newer</a>{% endif %} {% if more %}<a href="/notes?page={{ number + 1 }}" rel="next">Older</a>{% endif %} </nav></section>from "@/components/NoteCard.nexy" import NoteCardfrom nexy import useSearchParamsfrom src.notes import notes_page params = useSearchParams()error = params.get("error", "")asked = params.get("page", "1")number = max(int(asked), 1) if asked.isdigit() else 1found = notes_page(number)notes = found[0]more = found[1]<section class="app-page"> <h1>Notes</h1> {% if error %} <p class="note-error" role="alert">{{ error | e }}</p> {% endif %} <form method="post" action="{{ __actions_path['create_note'] }}"> <input name="text" placeholder="A new note" maxlength="200" required> <button type="submit">Add</button> </form> {% for note in notes %} <NoteCard id="{{ note.id }}" text="{{ note.text }}" /> {% endfor %} <nav class="note-pages" aria-label="Pages of notes"> {% if number > 1 %}<a href="/notes?page={{ number - 1 }}" rel="prev">Newer</a>{% endif %} {% if more %}<a href="/notes?page={{ number + 1 }}" rel="next">Older</a>{% endif %} </nav></section>rel="prev" et rel="next" indiquent aux navigateurs et aux moteurs de recherche comment les pages se suivent, et aria-label nomme les liens pour un lecteur d'écran.
Ajoutez des notes jusqu'à ce qu'il y en ait plus de cinq : la liste s'arrête à cinq, avec un lien Plus ancien. Cela mène à /notes?page=2, qui a un lien de retour Newer.
Ce que tu as appris
offsetetlimitlisent une page ; demander une ligne de plus indique si une autre page suit.useSearchParams()lit?page=; une valeur du visiteur est vérifiée avant d'être utilisée.rel="prev"etrel="next"relient les pages des navigateurs, des robots d'exploration et des lecteurs d'écran.
Prochaines étapes
- Unité 3, partie 10 : créez un compte et connectez-vous
- SQLite : index, pragmas et tests sur une base de données en mémoire