DokuEinheit 2: Daten

Erstellen Sie eine Notizen-App mit Nexy, Teil 9: Paginieren Sie die Notizen

Teil 9 zeigt jeweils fünf Notizen mit Links zur nächsten und vorherigen Seite, gelesen aus dem page der URL: /notes?page=2.

Bevor Sie beginnen: die App von Teil 8.

Bitten Sie die Datenbank um eine Seite

OFFSET überspringt die Notizen der vorherigen Seiten, LIMIT behält fünf. Wenn Sie nach mehr als fünf fragen, erfahren Sie kostenlos, ob eine nächste Seite existiert:

src/notes.py
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_SIZE
src/notes.py
from 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_SIZE

Lesen Sie die Seitenzahl aus der URL ab

Das page der Abfragezeichenfolge ist vom Besucher gesendeter Text: Alles, was keine positive Zahl ist, fällt auf die erste Seite zurück, sodass /notes?page=abc immer noch antwortet.

src/routes/notes/index.nexy
---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>
src/apps/notes/notes_view.nexy
---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" und rel="next" teilen Browsern und Suchmaschinen mit, wie die Seiten aufeinander folgen, und aria-label benennt die Links für einen Screenreader.

Fügen Sie Notizen hinzu, bis mehr als fünf vorhanden sind: Die Liste endet bei fünf mit einem Link Älter. Es führt zu /notes?page=2, wo es einen Link zu Neuer gibt.

Was du gelernt hast

  • offset und limit lesen eine Seite; Wenn man nach einer Zeile mehr fragt, sagt man, ob eine weitere Seite folgt.
  • useSearchParams() lautet ?page=; Ein Wert des Besuchers wird vor seiner Verwendung überprüft.
  • rel="prev" und rel="next" verlinken die Seiten für Browser, Crawler und Screenreader.

Nächste Schritte

Auf GitHub bearbeiten

Enter öffnet das Ergebnis, Esc schließt.