Skip to content

refactor: extract helpers and enhance fixtures#43

Merged
PascalRepond merged 1 commit intomainfrom
rep-dev
Jan 6, 2026
Merged

refactor: extract helpers and enhance fixtures#43
PascalRepond merged 1 commit intomainfrom
rep-dev

Conversation

@PascalRepond
Copy link
Copy Markdown
Owner

  • Also deletes cron from Dockerfile as it doesn't seem to work in production. Should probably use an external tool to run auto backups at regular intervals.
  • Change Video Game icon to differentiate it better from Series icon.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 6, 2026

📝 Walkthrough

Walkthrough

Refactors media filtering/query logic into new modules, delegates view context building to queries.py, removes cron setup from Docker and entrypoint, updates fixture texts and some titles, changes GAME icon mapping, and adds an optional VSCode setting.

Changes

Cohort / File(s) Summary
Infrastructure cleanup
Dockerfile, scripts/entrypoint.sh
Removed installation of cron, deleted cron job setup (daily backup), and removed cron service initialization and runtime cron health checks from the entrypoint.
Configuration
.vscode/settings.json
Added optional VSCode key python-envs.pythonProjects with an empty list value.
Filtering & sorting utilities
src/core/filters.py
New module adding functions to resolve sorting, extract filters from requests, retrieve field choices, and apply contributor/type/status/score/date/cover/review filters with robust handling of malformed inputs.
Query & context building
src/core/queries.py
New module adding build_search_queryset(query) for case-insensitive multi-field search and build_media_context(request) to orchestrate search, filters, sorting, and pagination into a renderable context.
View refactoring
src/core/views.py
Replaced local helper-based media context construction with a call to build_media_context(), removing now-unused local helpers and imports.
UI icon update
src/core/templatetags/media_tags.py
Changed MEDIA_TYPE_ICONS["GAME"] from "computer-desktop" to "puzzle-piece".
Fixture data
src/core/fixtures/sample_data.json
Replaced/expanded many review texts (translated some French titles to English), converting short reviews to longer Markdown-formatted English content; JSON schema unchanged.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client (browser)
  participant View as Django View
  participant Queries as queries.build_media_context
  participant Filters as filters.apply_filters
  participant DB as Database (Media/Agent)
  participant Paginator as Django Paginator

  Client->>View: GET /media?search=...&filters...
  View->>Queries: build_media_context(request)
  Queries->>Filters: extract_filters + resolve_sorting
  Filters->>DB: query Media with filters (joins to Agent for contributors)
  DB-->>Filters: filtered queryset
  Filters-->>Queries: filtered queryset
  Queries->>DB: apply search (if present) / order_by
  DB-->>Queries: sorted queryset
  Queries->>Paginator: paginate(queryset, per_page=20)
  Paginator-->>Queries: page_obj, media_list
  Queries-->>View: context dict (media_list, page_obj, filters, sort, choices)
  View-->>Client: render template with context
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'refactor: extract helpers and enhance fixtures' accurately reflects the main changes: extracting media filtering/querying helpers into separate modules and updating fixture data.
Description check ✅ Passed The description is related to the changeset, covering the removal of cron, icon change, and refactoring work present in the actual changes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2fbed7b and 8fd5fb1.

📒 Files selected for processing (8)
  • .vscode/settings.json
  • Dockerfile
  • scripts/entrypoint.sh
  • src/core/filters.py
  • src/core/fixtures/sample_data.json
  • src/core/queries.py
  • src/core/templatetags/media_tags.py
  • src/core/views.py
💤 Files with no reviewable changes (1)
  • scripts/entrypoint.sh
🚧 Files skipped from review as they are similar to previous changes (3)
  • .vscode/settings.json
  • src/core/views.py
  • src/core/templatetags/media_tags.py
🧰 Additional context used
🧬 Code graph analysis (2)
src/core/fixtures/sample_data.json (2)
src/core/migrations/0003_media_review_media_review_date_media_score_and_more.py (1)
  • Migration (9-41)
src/core/migrations/0008_media_review_rendered_alter_media_review.py (1)
  • Migration (24-43)
src/core/filters.py (2)
src/core/models.py (2)
  • Agent (95-106)
  • Media (109-227)
src/tests/core/test_views.py (1)
  • TestFilteringHelper (279-326)
🔇 Additional comments (10)
Dockerfile (2)

32-35: LGTM! Cron removal aligns with container best practices.

Removing cron from the container is the right approach. Containerized cron has known limitations with signal handling, logging, and process management. Using external schedulers (Kubernetes CronJobs, cloud schedulers, or systemd timers) is the recommended pattern for scheduled tasks in production.


55-57: Document the external scheduling approach for Docker deployments.

The backup script retention is appropriate, but documentation is incomplete. While README.md covers backup commands (poe-based utilities), it does not explain how to set up external scheduling to invoke the backup script in Docker deployments. Add guidance on configuring external schedulers—such as Kubernetes CronJob, systemd timer, or cloud scheduler service—to call the backup script in the running container.

src/core/fixtures/sample_data.json (1)

109-109: Fixture enhancements look good.

The updated reviews with Markdown formatting (headings, bold, italics) and the title translations to English will provide richer test data for Markdown rendering and improve consistency for development. The changes align well with the MarkdownField usage in the Media model.

Also applies to: 120-125, 141-141, 152-157, 188-188, 204-204, 220-220, 235-235, 246-251, 267-267, 283-283, 298-298, 324-329, 345-345, 360-360, 371-376, 392-392, 408-408, 450-455

src/core/queries.py (2)

10-22: Good fix for the pub_year search.

The previous issue with icontains on IntegerField has been correctly addressed. Parsing the query as an integer and using Q(pub_year__exact=parsed_year) with a try/except fallback is the right approach for searching numeric fields.


25-58: Well-structured context builder.

The function cleanly consolidates the common logic for media listing views. The delegation to filter utilities keeps this focused on orchestration, and the use of get_page() ensures graceful handling of invalid page numbers.

src/core/filters.py (5)

12-23: Good security practice with sort field whitelist.

The validation against a predefined set of valid fields before constructing the sort string prevents potential issues with arbitrary field ordering. The fallback to default_field ensures safe behavior for invalid inputs.


26-70: Filter extraction handles edge cases well.

The graceful handling of malformed score values in the display name generation (lines 64-68) prevents crashes from invalid URL parameters. The has_any flag provides a clean way for templates to detect active filters.


107-121: Solid score filter implementation.

The dynamic Q object construction handles the "none" case for null scores cleanly. One minor note: if all provided score values are malformed, the function returns an empty Q() which matches all records - this is acceptable as graceful degradation for invalid input.


124-142: Clean date and content filter implementation.

Using contextlib.suppress for date validation is idiomatic Python. The combined Q(field__isnull=True) | Q(field="") checks correctly handle both null and empty string cases for optional fields.


145-152: Clean filter orchestration.

The function provides a single entry point for applying all filters, keeping the calling code in build_media_context clean and focused.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI Agents
In @src/core/queries.py:
- Around line 12-17: The lookup Q(pub_year__icontains=query) is invalid for the
IntegerField pub_year and must be replaced; in the Media.objects.filter call
remove that icontains clause and instead add a numeric-year check by trying to
parse query to an int and, if successful, include Q(pub_year__exact=parsed_year)
(or implement the alternative prefix-range logic: compute start/end years from a
numeric prefix and add Q(pub_year__gte=start, pub_year__lte=end)); ensure this
change is applied where Media.objects.filter and the
Q(pub_year__icontains=query) expression appear and keep the other Q(...) clauses
and .distinct() intact.
🧹 Nitpick comments (1)
src/core/views.py (1)

15-15: Clean refactoring to centralized context builder!

The extraction of media context-building logic into src/core/queries.py successfully improves code organization and reusability. Both views now delegate to the centralized build_media_context function.

💡 Optional: Consider simplifying the return signature

Both views unpack build_media_context as _, context = build_media_context(request), discarding the first page_obj element since it's already included in the returned context dict (context["page_obj"]).

Consider modifying build_media_context in src/core/queries.py to return only the context dict, eliminating the redundant tuple:

-def build_media_context(request):
-    """
-    Build and filter media queryset from request parameters.
-
-    Returns a tuple of (page_obj, context_dict) ready for rendering.
-    ...
-    """
-    ...
-    return page_obj, context
+def build_media_context(request):
+    """
+    Build and filter media queryset from request parameters.
+
+    Returns a context dict ready for rendering.
+    ...
+    """
+    ...
+    return context

Then simplify the view calls:

-_, context = build_media_context(request)
+context = build_media_context(request)

This is optional since the current implementation works correctly—it just has a minor redundancy in the API.

Also applies to: 22-23, 88-88

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e45e823 and 2fbed7b.

📒 Files selected for processing (8)
  • .vscode/settings.json
  • Dockerfile
  • scripts/entrypoint.sh
  • src/core/filters.py
  • src/core/fixtures/sample_data.json
  • src/core/queries.py
  • src/core/templatetags/media_tags.py
  • src/core/views.py
💤 Files with no reviewable changes (1)
  • scripts/entrypoint.sh
🧰 Additional context used
🧬 Code graph analysis (3)
src/core/queries.py (2)
src/core/filters.py (4)
  • apply_filters (145-152)
  • extract_filters (26-70)
  • get_field_choices (73-79)
  • resolve_sorting (12-23)
src/core/models.py (1)
  • Media (109-227)
src/core/filters.py (1)
src/core/models.py (2)
  • Agent (95-106)
  • Media (109-227)
src/core/views.py (2)
src/core/queries.py (1)
  • build_media_context (20-55)
src/core/utils.py (2)
  • create_backup (46-118)
  • delete_orphan_agents_by_ids (32-43)
🔇 Additional comments (16)
.vscode/settings.json (1)

14-15: LGTM!

VSCode configuration updates are appropriate and have no impact on the application runtime.

src/core/templatetags/media_tags.py (1)

10-10: LGTM!

The icon change from "computer-desktop" to "puzzle-piece" for the GAME media type improves visual differentiation from the TV/Series icon, as stated in the PR objectives.

src/core/fixtures/sample_data.json (1)

1-462: LGTM!

The fixture data enhancements successfully standardize content to English and add richer, Markdown-formatted descriptions. These changes align with the PR objective to "enhance test/dev fixtures" and provide better sample data for development and testing.

Dockerfile (1)

32-35: LGTM!

The removal of cron aligns with the PR objectives, which note that cron doesn't work reliably in production containers. The backup script remains available at /app/daily_backup.sh for execution via external scheduling tools (e.g., Kubernetes CronJobs, host-level cron, or CI/CD pipelines).

src/core/queries.py (2)

1-8: LGTM! Clean module structure.

The imports and organization are appropriate for the extracted utilities.


20-55: Verify the redundant return of page_obj.

The function returns page_obj both directly in the tuple and as a key in the context dict (Line 46). This redundancy might be intentional for different consumption patterns, but it's worth confirming.

Is the dual return intentional? If callers only need the context dict, consider simplifying to return just the context:

return context

Or document why both are needed in the docstring.

src/core/filters.py (10)

1-10: LGTM! Well-organized imports.

The imports are appropriate and the module is clearly documented.


12-23: LGTM! Robust sorting validation.

The function correctly validates sort fields against a whitelist and handles both ascending/descending order with proper defaults.


26-70: LGTM! Comprehensive filter extraction with good error handling.

The function robustly extracts filters with proper handling of malformed inputs and provides user-friendly display names for the UI.


73-79: LGTM! Simple and clear utility.


82-90: LGTM! Safe contributor filtering.

The function properly handles missing contributors with .first() and returns a clear tuple result.


93-97: LGTM! Clean type filtering.


100-104: LGTM! Clean status filtering.


107-121: LGTM! Robust score filtering with proper null handling.

The function correctly handles both the "none" case for unrated media and numeric scores with appropriate error handling for malformed inputs.


124-142: LGTM! Excellent defensive programming for date and content filters.

The use of contextlib.suppress provides robust error handling for malformed date inputs, and the logic for empty/filled content checks is correct.


145-152: LGTM! Clean orchestration of all filters.

The function properly composes all filtering operations and maintains a clear return signature.

Comment thread src/core/queries.py Outdated
- Also deletes cron from Dockerfile as it doesn't seem to work in
production. Should probably use an external tool to run auto backups at
regular intervals.
- Changes Video Game icon to differentiate it better from Series icon.
- Fixes search by year not matching pub_year field.

Co-Authored-by: Pascal Repond <pascal.repond@rero.ch>
@PascalRepond PascalRepond merged commit bc0bd4b into main Jan 6, 2026
3 checks passed
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