2.3.4
2.3.4 — Performance, correctness, and hygiene
A focused pass on long-standing bugs and the publications/index page perf cliff. No breaking changes — drop-in upgrade from 2.3.2. 49 unit tests now pass (up from 0 at the start of the pass).
⚡ Performance
/publications/is ~8× faster end-to-end. Addedprefetch_related('authors', 'projects', 'keywords')to the Publication queryset across/publications/,/,/project/<n>/, and/member/<n>/. The snippet loopspub.authors.all/pub.projects.all/pub.keywords.allper row, so the prefetch eliminates the bulk of the N+1. Measured locally: 617 queries / 275.83 ms → 60 queries / 35 ms. (d4f6d65)- Talk and Video pages also faster via the same
select_related+prefetch_relatedshape across index/project/member views. Index: 348 → 154 queries / 174 → 104 ms. Project page: 85 → 63 queries / 71 → 39 ms. (1cae31c) - Thumbnails now lazy-load.
loading="lazy"added to all 9 artifact-thumbnail<img>tags indisplay_pub_snippet.htmlanddisplay_talk_snippet.html. Below-the-fold images defer until scrolled into view. Particularly noticeable on slow mobile networks. (a51d812)
🐛 Bug fixes
serve_pdfno longer crashes on duplicate substring matches and no longer enables PDF-filename enumeration. ReplacedPublication.objects.get(pdf_file__icontains=filename)withfilter(pdf_file__iendswith=filename).first(). Preserves the fuzzydifflibfallback for stale external links (#1173). (f78fc14)- News pages with deleted authors no longer crash.
News.authorisnull=True, on_delete=SET_NULL. Previously thenews_itemview raisedAttributeErrorand thenews_listingtemplate raisedNoReverseMatchwhenever a News row's author had been removed. Both call sites guarded. (1c0d6c0) delete_unused_filesno longer crashes on artifacts with no PDF or thumbnail. Three call sites guarded (talk PDF, pub PDF, pub thumbnail), matching the existing poster-branch pattern (#1254). (202b1bb)views/member.pyMultipleObjectsReturned handler now references a real field. The fallback usedorder_by('-modified_date')which doesn't exist on Person; switched to-bio_datetime_modified(#1254). (202b1bb)Artifact.do_filenames_need_updatingchecks the correct fields. Theraw_fileandthumbnailbranches were both comparingpdf_file.name(copy-paste bug); each now checks its own field. (c7abcf7)News.save()slug-collision loop excludes self. Admin-cleared slugs no longer bump unnecessarily on re-save. (c7abcf7)Person.save()no longer leaks file descriptors when assigning the Star Wars fallback image — wrapped in try/finally that closes aftersuper().save()reads the file. (c7abcf7)
🧹 Hygiene
- Production file-log level is now INFO instead of DEBUG. The file handler in
settings.pyis conditional onDEBUG— local dev keeps verbose file logs; production logs are much smaller and no longer expose per-request URLs or_logger.debugpayloads at/logs/debug.log. (~75 MB of stale rotateddebug.log*files in~/ml-www-prodwere also cleaned up manually.) (31f2b4f) - Stray
print()statements removed frommodels/projectils/ml_utils.py. (14da008) - Broken
_logger.debugpayload fixed inviews/people.py:62— the second positional arg was being silently dropped. (14da008) - Duplicate
Coalesceimport removed frommodels/personnmodels/project_role.py:88` per PEP 8 (#1254). (f0d44c1) - Dead code removed:
get_closest_filename_from_filesystemhelper inserve_pdf.py. (f78fc14)
🧪 Tests
The test suite went from effectively empty to 49 unit tests covering BibTeX citation, get_current_member_count, Artifact.do_filenames_need_updating, serve_pdf paths, plu_biocoverage. AllSimpleTestCase` — no DB setup required,runs in <100 ms.
🛠 Known follow-ups (not in this release)
- Production-side Apache exemption for
/media/publications/(#1173) — theserve_pdfview's code is now safe to expose, but Apache on production still serves/media/publications/*directly. The test serve IT in Dec 2025; the prod-side ask is in flight. /logs/exposure design check — currently public by design perdocs/DEPLOYMENT.md. Open question whether to add an IP allowlist or basic auth; not load-bearing since prod logs are now INFO-only.- DB-touching test infrastructure — would unlock
assertNumQueriesregression tests for the perf wins and view-level integration tests for the null-guard logic.