Nobody has started this yet — be first.
Business impact
As the number of polls grows, "every poll, newest first" stops being useful for real clients -- a dashboard, a "my polls" management page, or a moderation view that only cares about currently-live polls all need to ask the API for a subset instead of fetching everything and filtering client-side. Client-side filtering doesn't even work correctly once pagination is involved (page 1 of "all polls" is not the same as page 1 of "my active polls"), so every consumer of this endpoint is stuck working around a gap that should be closed in the API itself.
Problem
GET /api/polls/ always returns every poll (paginated, 20 per page), newest first, with no way to narrow the list. PollViewSet.queryset is a static Poll.objects.all().select_related(...).prefetch_related(...) -- there is no get_queryset override reading anything from the request.
Current behavior
GET /api/polls/?is_active=true (or ?created_by=<username>) is silently ignored -- the query parameter has no effect and the full, unfiltered list of polls comes back every time.
Expected behavior
GET /api/polls/ supports two optional query parameters, combinable: ?is_active=true / ?is_active=false (only polls whose is_active flag matches), and ?created_by=<username> (only polls created by the user with that username). With no query params, behavior is unchanged (every poll, as today).
Steps to reproduce
cd django/poll_app source .venv/bin/activate python manage.py runserver &
curl -s "http://127.0.0.1:8000/api/polls/?is_active=true" | jq '.results | length'
curl -s "" | jq '.results | length'
Why this matters
ModelViewSet calls self.get_queryset() to build the base queryset for list() (and other actions); overriding it is the one place this kind of narrowing belongs. This is a foundational piece of API surface that a lot of realistic UI depends on, and it's currently entirely absent -- no stub exists to extend, because nothing resembling this exists yet.
Suggested approach
ModelViewSet calls self.get_queryset() to build the base queryset for list() (and other actions); overriding it lets you start from the existing Poll.objects.all().select_related(...).prefetch_related(...) and narrow it based on self.request.query_params. Think about how to parse is_active as a boolean from a query string ("true"/"false" arrive as strings, not Python bools), what the queryset looks like when the param isn't present at all, and filtering created_by by username, not id -- the API never exposes a raw user id to clients (PollSerializer.created_by is source="created_by.username"), so a client can only reasonably send back the username it was shown, which means traversing the relation (created_by__username) rather than filtering on created_by_id.
Acceptance criteria
Verification
.venv/bin/python manage.py test practicetickets.test_ticket04_poll_list_filtering -v 2
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
$git checkout -b feat/poll-list-filteringFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/poll-list-filteringSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign inhttp://127.0.0.1:8000/api/http://127.0.0.1:8000/admin/.env.example.envSECRET_KEYDEBUGDB_*CELERY_BROKER_URLmanage.py testOr via Docker (Postgres, Redis, Django with hot reload, and a Celery worker, all wired together, migrations run automatically on startup):
docker compose up --build
Work the tickets in practicetickets/ (ticket01 through ticket07); each names one dedicated Django test module:
./practicetickets/run_tickets.sh # all 7, clean pass/fail summary
./practicetickets/run_tickets.sh -v # summary + each test's full output
.venv/bin/python manage.py test practicetickets.test_ticket01_permission_check_inverted -v 2 # a single ticket
Three of the seven tickets (01, 02, 03) also collaterally break pre-existing tests in polls/tests/; run .venv/bin/python manage.py test polls -v 2 to confirm the main suite is back to fully green once those are fixed. No Redis or Celery worker is required for any of this -- settings.py forces CELERY_TASK_ALWAYS_EAGER = True whenever "test" appears in sys.argv.
Level 2
Implement a feature
Extend the system within its own patterns.