Skip to content

fix: add pagination to lead listing API - #670

Open
navashree9b11398 wants to merge 1 commit into
Kuldeeep18:mainfrom
navashree9b11398:fix/458-lead-pagination
Open

fix: add pagination to lead listing API#670
navashree9b11398 wants to merge 1 commit into
Kuldeeep18:mainfrom
navashree9b11398:fix/458-lead-pagination

Conversation

@navashree9b11398

@navashree9b11398 navashree9b11398 commented Jul 12, 2026

Copy link
Copy Markdown

Pull Request

🔗 Related Issue

Closes #458

📝 Summary of Changes

  • Added a dedicated LeadPagination class using Django REST Framework PageNumberPagination.
  • Applied pagination only to LeadViewSet.
  • Added support for the page_size query parameter.
  • Limited the maximum page size to 200.
  • Added deterministic ordering using -created_at.
  • Updated existing tests and added pagination-specific tests.

🏷️ Type of Change

  • [x ] 🐛 Bug fix
  • ✨ New feature
  • ♻️ Refactor
  • 📝 Documentation update
  • 🎨 UI / Style change
  • 🔧 Chore

🧪 Testing

Executed the lead test suite locally.

Command used:

python manage.py test leads

**Steps to test:**
1. Run the backend server.
2. Send a GET request to /api/v1/leads/.
3. Verify the response includes count, next, previous and results.
4. Test page_size query parameter (e.g. ?page_size=10).
5. Verify page_size greater than 200 is capped at 200.

---

## 📸 Screenshots (if applicable)
Not applicable.

## ✅ Checklist

* [x] No merge conflicts
* [x] Changes follow the project guidelines
* [ ] Documentation updated (if applicable)
* [x] Related issue linked
* [x] Changes tested locally (if applicable)


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Lead listings now support pagination with 50 leads per page by default.
  * Page size can be customized through the `page_size` parameter, up to 200 leads.

* **Improvements**
  * Leads are consistently displayed from newest to oldest.
  * Lead filters continue to work correctly across paginated results.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The lead listing API now returns paginated, newest-first results with configurable page sizes capped at 200. Existing organization and filter tests use the paginated response shape, and new tests cover pagination limits.

Changes

Lead listing pagination

Layer / File(s) Summary
Pagination and lead ordering
backend/leads/views.py
Adds LeadPagination, wires it to LeadViewSet, and orders distinct leads by descending creation time.
Pagination-aware API tests
backend/leads/tests.py
Updates listing and filter assertions for paginated responses and adds coverage for default, requested, and capped page sizes.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant LeadViewSet
  participant LeadPagination
  Client->>LeadViewSet: Request /api/v1/leads/
  LeadViewSet->>LeadPagination: Paginate ordered lead queryset
  LeadPagination-->>LeadViewSet: Return page results and metadata
  LeadViewSet-->>Client: Return paginated response
Loading

Possibly related issues

  • Kuldeeep18/LeadOrbit issue 35: Concerns the same lead API pagination behavior.
  • Kuldeeep18/LeadOrbit issue 656: Concerns adding DRF pagination with a default page size of 50.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Pagination and ordering requirements appear covered, but the PR summary does not show the required select_related("assigned_to") optimization. Add select_related("assigned_to") to the lead queryset and verify the paginated response still includes count, next, and previous.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The reported changes stay focused on lead-list pagination, ordering, and test updates with no clear unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding pagination to the lead listing API.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
backend/leads/tests.py (1)

466-503: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add test for page=2 navigation and ordering verification.

The pagination tests cover default page size, page_size override, and max capping, but don't test actual page navigation or ordering. Issue #458 mentions page=2&page_size=100 as a use case. Consider adding:

  1. A test requesting ?page=2 and verifying it returns the remaining 10 leads (60 total, default page_size 50).
  2. A test verifying next is non-null on page 1 and previous is null on page 1.
  3. A test verifying results are ordered newest-first by created_at.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/leads/tests.py` around lines 466 - 503, Extend LeadPaginationAPITests
with coverage for page navigation and ordering: request page=2 with the default
page size and assert the remaining 10 results, verify page 1 has a non-null next
link and null previous link, and assert results are ordered newest-first by
created_at. Reuse the existing self.leads fixtures and pagination response
fields.
backend/leads/views.py (1)

88-88: 🚀 Performance & Scalability | 🔵 Trivial

LeadSerializer.get_tags issues a per-lead query (N+1).

Even with pagination at 50 leads per page, get_tags runs Tag.objects.filter(tagged_leads__lead=obj) for each lead — 50 extra queries per page. Consider adding prefetch_related to the queryset to batch-fetch tags:

from django.db.models import Prefetch
qs = qs.prefetch_related(
    Prefetch('lead_tags__tag', queryset=Tag.objects.filter(organization=self.request.user.organization))
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/leads/views.py` at line 88, Update the queryset construction before
the final distinct/order_by return to prefetch the serializer’s lead tag
relation using Prefetch, limiting the nested Tag queryset to
self.request.user.organization. Reuse the existing lead_tags__tag relationship
so LeadSerializer.get_tags can use prefetched data and avoid one query per lead.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/leads/tests.py`:
- Line 404: Rename the ambiguous comprehension variable `l` to `lead` in the
affected expressions throughout the tests, including the result-processing code
around the `emails` assignment and the corresponding lines at 411, 418, 428,
448, and 462, while preserving the existing behavior.

---

Nitpick comments:
In `@backend/leads/tests.py`:
- Around line 466-503: Extend LeadPaginationAPITests with coverage for page
navigation and ordering: request page=2 with the default page size and assert
the remaining 10 results, verify page 1 has a non-null next link and null
previous link, and assert results are ordered newest-first by created_at. Reuse
the existing self.leads fixtures and pagination response fields.

In `@backend/leads/views.py`:
- Line 88: Update the queryset construction before the final distinct/order_by
return to prefetch the serializer’s lead tag relation using Prefetch, limiting
the nested Tag queryset to self.request.user.organization. Reuse the existing
lead_tags__tag relationship so LeadSerializer.get_tags can use prefetched data
and avoid one query per lead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 13d28c7e-0f2a-4306-97d5-caa8fe2f25ad

📥 Commits

Reviewing files that changed from the base of the PR and between 4a33158 and 0acc85e.

📒 Files selected for processing (2)
  • backend/leads/tests.py
  • backend/leads/views.py

Comment thread backend/leads/tests.py
resp = self._get(status='active')
self.assertEqual(resp.status_code, status.HTTP_200_OK)
emails = {l['email'] for l in resp.data}
emails = {l['email'] for l in resp.data['results']}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Ruff E741: ambiguous variable name l.

Ruff flags l as ambiguous (E741) on lines 404, 411, 418, 428, 448, and 462. Rename to lead for clarity and lint compliance.

🔧 Proposed fix
- emails = {l['email'] for l in resp.data['results']}
+ emails = {lead['email'] for lead in resp.data['results']}

Also applies to: 411-411, 418-418, 428-428, 448-448, 462-462

🧰 Tools
🪛 Ruff (0.15.20)

[error] 404-404: Ambiguous variable name: l

(E741)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/leads/tests.py` at line 404, Rename the ambiguous comprehension
variable `l` to `lead` in the affected expressions throughout the tests,
including the result-processing code around the `emails` assignment and the
corresponding lines at 411, 418, 428, 448, and 462, while preserving the
existing behavior.

Source: Linters/SAST tools

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.

[Performance] Lead listing API returns all records without pagination - large orgs get slow or OOM responses

1 participant