Skip to content

feat(nowe_raporty): wybór sortowania raportu — wg nazwisk autorów (FD467) - #773

Open
mpasternak wants to merge 2 commits into
devfrom
feat/fd467-sortowanie-po-autorach
Open

feat(nowe_raporty): wybór sortowania raportu — wg nazwisk autorów (FD467)#773
mpasternak wants to merge 2 commits into
devfrom
feat/fd467-sortowanie-po-autorach

Conversation

@mpasternak

@mpasternak mpasternak commented Aug 16, 2026

Copy link
Copy Markdown
Member

Odblokowany. django-flexible-reports 0.5.0 jest na PyPI, bump + uv lock dojechały commitem 37085d7, testy przechodzą przeciw wydanej paczce. PR gotowy do review.

Zgłoszenie

FD467, Biblioteka Naukowa IHiT (Anna Wołodko). Klientka przysłała Publikacje.docx — spis w formie, w jakiej wchodzi do sprawozdania rocznego — i prosi, żeby dało się taki wydruk zrobić z BPP. Kluczowe zdanie: „spis powinien być uporządkowany wg nazwisk autorów".

Załącznik to płaska, numerowana lista alfabetyczna wg pierwszego autora (Antoniewicz-Papis → Beauverd → Budziszewska → Carcao → Cardona-Benavides → Cesaro…). To istotne: nie chodzi o sekcje per-autor, tylko o porządek wierszy.

Dlaczego to nie było możliwe

Kolejność wierszy jest własnością tabeli flexible_reports.Table — inline ColumnOrder (rok malejąco, potem opis), czytany w adapterze i wstawiany do Meta.order_by. Czyli stała zapisana w bazie, w dodatku wspólna dla wszystkich raportów: seeding/__init__.py tworzy jeden obiekt Table obsługujący 4 raporty × 12 sekcji. Przestawienie go zmieniłoby sortowanie wszystkim.

Rozwiązanie

Pole „Sortowanie" w formularzu raportu, obok „Formatu wyjściowego":

Wariant Porządek
Rok (malejąco), potem opis bibliograficzny dotychczasowy, domyślny
Nazwiska autorów (alfabetycznie) nowy

Wybór jedzie querystringiem tak samo jak _export, więc obejmuje również eksport do DOCX/XLSX. Widok przekłada go na Report.set_order_by() — hook nadpisujący ColumnOrder na jeden render, bez dotykania definicji w bazie.

Sedno: po czym właściwie sortujemy

Po Rekord.opis_bibliograficzny_autorzy_cacheArrayField ["Nazwisko Imiona", ...] w kolejności autorstwa. PostgreSQL porównuje tablice element po elemencie, więc wychodzi porządek wg nazwiska pierwszego autora, z kolejnymi autorami jako rozstrzygnięciem remisu. Dokładnie to, o co prosi zgłoszenie.

To jedyne miejsce, w którym „nazwisko pierwszego autora" jest sortowalnym skalarem. Przez relację (autorzy__autor__nazwisko) sortować się nie da: JOIN po relacji wielowartościowej zduplikowałby wiersze, a Column.clean() i tak odrzuca taką ścieżkę w dot-notation. Pole denormalizowane dla opisu bibliograficznego okazuje się przypadkiem jedynym wyjściem.

Bo to założenie o bazie, a nie o naszym kodzie, ma własny test — test_rekord_sortuje_sie_po_nazwisku_pierwszego_autora. Cała funkcja na nim stoi.

tytul_oryginalny_sort jako trzeci klucz nie jest ozdobą: bez niego dwie prace tego samego autora z tego samego roku mają kolejność niezdeterminowaną, więc ten sam raport wygenerowany dwa razy potrafiłby się różnić.

Nowy moduł sortowanie.py

Warianty (etykiety dla formularza) i mapowanie na pola ORM (dla widoku) w jednym miejscu, na wzór poziomy.py. Rozdzielone groziłyby cichym rozjechaniem: formularz oferowałby wariant, którego widok nie zna, i raport wychodziłby po prostu posortowany domyślnie — bez żadnego błędu.

Domyślna wartość per instalacja — za darmo

Nie trzeba jej nigdzie modelować. RaportFormView stoi na FormDefaultsMixin, a form_class_dla() buduje klasę o stabilnej, unikalnej nazwie per slug raportu (właśnie po to, żeby formdefaults nie mieszał defaultów między raportami). Redaktor ustawia więc domyślne sortowanie per instalacja i per raport z panelu domyślnych wartości formularzy. IHiT dostaje „zawsze po nazwiskach" bez pola w modelu i bez migracji.

Przy okazji: POLA_ZAAWANSOWANEPOLA_PRZEKAZYWANE

Lista steruje wyłącznie przekazywaniem do querystringu — o wyglądzie decyduje Layout. Po dodaniu sortowania, które w układzie stoi w głównym fieldsecie, dawna nazwa sugerowałaby nieistniejący związek z sekcją „Opcje zaawansowane". Dwa użycia w repo, oba zaktualizowane.

Testy

src/nowe_raporty/tests/test_sortowanie.py, pisane TDD (każdy oglądany na czerwono przed implementacją — w tym IndexError, który wykrył brakujący denorms.flush() w fixture):

  • test_sortowanie_po_autorach_ustawia_order_by_raportu — okablowanie widoku
  • test_bez_parametru_raport_zachowuje_kolejnosc_z_columnorder — regresja dla istniejących instalacji
  • test_rekord_sortuje_sie_po_nazwisku_pierwszego_autora — założenie o PostgreSQL
  • test_formularz_domyslnie_nie_zmienia_sortowania
  • test_formularz_przekazuje_wybor_sortowania_do_url — wybór przeżywa skok formularz → redirect → widok

Lokalnie: 69 passed w src/nowe_raporty/ (cała aplikacja, nie tylko nowe testy). pre-commit czysto.

Zależność

Wymaga django-flexible-reports>=0.5.0mpasternak/django-flexible-reports#14 (Report.set_order_by()). Bump w pyproject.toml + uv lock dokładam osobnym commitem po wydaniu pakietu; dziś uv lock nie ma czego zrezolwować, więc commit z bumpem zostawiłby drzewo niespójne.

Kolejność: zmerguj i wydaj #14 → dopycham bump tutaj → PR gotowy do scalenia.

Poza zakresem

Klientka dostanie 12 alfabetycznych list (po jednej na sekcję 1.1, 1.2, 2.1…), a jej dokument to jedna płaska lista. Płaski raport składa się w adminie, bez kodu (nowy Report z jedną sekcją catchall) — przygotuję go osobno i pokażę oba warianty.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WSUsgzYoDNnXpXGAn5otJg

@mpasternak
mpasternak marked this pull request as ready for review August 18, 2026 22:25
@mpasternak
mpasternak force-pushed the feat/fd467-sortowanie-po-autorach branch from 37085d7 to 0b484f4 Compare August 18, 2026 22:27
mpasternak and others added 2 commits August 19, 2026 14:34
…467)

Zgłoszenie FD467 (Biblioteka Naukowa IHiT) prosi o wydruk z BPP w formie,
w jakiej spis wchodzi do sprawozdania rocznego: uporządkowany alfabetycznie
wg nazwisk autorów. Dziś kolejność wierszy jest własnością tabeli
flexible_reports (inline ColumnOrder: rok malejąco, potem opis), a więc
stałą zapisaną w bazie i wspólną dla wszystkich czterech raportów — jedna
tabela obsługuje 4 raporty x 12 sekcji.

Formularz raportu dostaje pole "Sortowanie" z dwoma wariantami: dotychczasowy
(domyślny, bez zmian) i alfabetyczny wg nazwisk. Wybór jedzie querystringiem
tak samo jak _export, więc obejmuje też eksport do DOCX/XLSX, a widok
generujący przekłada go na Report.set_order_by() — hook nadpisujący
ColumnOrder na jeden render, bez ruszania definicji w bazie.

Sortujemy po opis_bibliograficzny_autorzy_cache: to ArrayField
["Nazwisko Imiona", ...] w kolejności autorstwa, a PostgreSQL porównuje
tablice element po elemencie, więc wychodzi porządek wg nazwiska PIERWSZEGO
autora (z kolejnymi jako rozstrzygnięciem remisu) — dokładnie to, o co prosi
zgłoszenie. To jedyne miejsce, w którym "nazwisko pierwszego autora" jest
sortowalnym skalarem: przez relację autorzy__autor__nazwisko sortować się nie
da, bo JOIN po relacji wielowartościowej zduplikowałby wiersze (a
Column.clean() i tak odrzuca taką ścieżkę w dot-notation). Test
test_rekord_sortuje_sie_po_nazwisku_pierwszego_autora pilnuje tego założenia
o bazie, bo cała funkcja na nim stoi.

Warianty i mapowanie na pola ORM siedzą w osobnym module sortowanie.py, na
wzór poziomy.py — formularz bierze stamtąd etykiety, widok pola ORM. Gdyby
były osobno, formularz mógłby oferować wariant, którego widok nie zna, a
raport po prostu wychodziłby posortowany domyślnie.

Przy okazji: POLA_ZAAWANSOWANE -> POLA_PRZEKAZYWANE. Lista steruje wyłącznie
przekazywaniem do querystringu (o wyglądzie decyduje Layout), a po dodaniu
"sortowania", które w układzie stoi w głównym fieldsecie obok formatu
wyjściowego, dawna nazwa sugerowałaby nieistniejący związek z sekcją "Opcje
zaawansowane".

Domyślnej wartości pola nie trzeba nigdzie modelować: RaportFormView stoi na
FormDefaultsMixin, a form_class_dla() buduje klasę o stabilnej nazwie per slug
raportu, więc redaktor ustawia default per instalacja i per raport z panelu
domyślnych wartości formularzy.

UWAGA: wymaga django-flexible-reports >= 0.5.0 (Report.set_order_by,
mpasternak/django-flexible-reports#14). Bump w pyproject.toml + uv lock
dokładam osobnym commitem po wydaniu pakietu — dziś lockfile nie ma czego
zrezolwować.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WSUsgzYoDNnXpXGAn5otJg
Wybór sortowania raportu stoi na Report.set_order_by(), który wchodzi
dopiero w 0.5.0 (mpasternak/django-flexible-reports#14). Bez tego pinu
instalacja z 0.4.2 wywalałaby się na AttributeError przy każdym raporcie
generowanym z wariantem "wg nazwisk autorów".

Bump siedzi w osobnym commicie, bo w chwili pisania funkcji pakiet nie był
jeszcze wydany i `uv lock` nie miał czego zrezolwować.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WSUsgzYoDNnXpXGAn5otJg
@mpasternak
mpasternak force-pushed the feat/fd467-sortowanie-po-autorach branch from 0b484f4 to e59c976 Compare August 19, 2026 12:37
@mpasternak

Copy link
Copy Markdown
Member Author

Zrebase'owany na dev po zmerdowaniu #782. Obie zmiany zależności współistnieją (django-flexible-reports>=0.5.0 + sqlparse>=0.6.0), uv lock --check przechodzi, lokalnie 69 passed w src/nowe_raporty/ przeciw wydanej 0.5.0 z PyPI.

CI: 24/24 zielone — 12/12 shardów, Build test-runner image, Check baseline freshness i pip-audit scan (ten ostatni dzięki #782). Gotowy do scalenia.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant