Skip to content

Add PlanFilter to Organization admin#659

Merged
allanlasser merged 5 commits into
masterfrom
claude/filter-organizations-by-plan-WuadY
May 12, 2026
Merged

Add PlanFilter to Organization admin#659
allanlasser merged 5 commits into
masterfrom
claude/filter-organizations-by-plan-WuadY

Conversation

@allanlasser
Copy link
Copy Markdown
Member

Helps us answer "How many orgs are subscribed to plan X?" with an update to the Django Admin.

Lets staff slice the Organization list view by the Plan an org is subscribed to, plus a "No plan" option for orgs with no Subscription rows. Cancelled subscriptions still count as subscribed, matching the semantics of Organization.plan.

Co-authored with Claude Opus 4.7

Lets staff slice the Organization list view by the Plan an org is
subscribed to, plus a "No plan" option for orgs with no Subscription
rows. Cancelled subscriptions still count as subscribed, matching
the semantics of Organization.plan.

https://claude.ai/code/session_01TMj6rVfo3TL8MwJC5h3enV
@allanlasser allanlasser temporarily deployed to squarelet-pi-claude-fil-tfyo3j April 24, 2026 20:32 Inactive
@allanlasser allanlasser temporarily deployed to squarelet-pi-claude-fil-tfyo3j April 27, 2026 13:46 Inactive
@duckduckgrayduck
Copy link
Copy Markdown
Contributor

Seems to work well- I do feel though that this would be greatly improved if we could mark who is currently subscribed vs. cancelled

@allanlasser
Copy link
Copy Markdown
Member Author

allanlasser commented Apr 28, 2026

I weighed that—orgs in a cancelled state will continue to have access to a plan until their subscription is deleted at the end of the term. It feels more accurate to include cancelled subscriptions in these groups, so they represent active subscriptions.

I think adding a column to this view would be the best way to identify orgs that won't have their subscription renew, and that's a good thing to add here.

@allanlasser allanlasser temporarily deployed to squarelet-pi-claude-fil-tfyo3j April 28, 2026 01:31 Inactive
@allanlasser
Copy link
Copy Markdown
Member Author

Now when filtering by a plan, a column's added to indicate whether the subscription will renew.

@allanlasser allanlasser temporarily deployed to squarelet-pi-claude-fil-tfyo3j April 28, 2026 12:19 Inactive
@allanlasser allanlasser force-pushed the claude/filter-organizations-by-plan-WuadY branch from c2334d7 to 76f1274 Compare April 28, 2026 12:20
@allanlasser allanlasser temporarily deployed to squarelet-pi-claude-fil-tfyo3j April 28, 2026 12:20 Inactive
@duckduckgrayduck
Copy link
Copy Markdown
Contributor

The number of SQL queries (as viewed in the Django debug toolbar) with this new column in the view radically jumped from ~30ish to ~200. This needs optimization

@allanlasser allanlasser temporarily deployed to squarelet-pi-claude-fil-tfyo3j May 1, 2026 14:41 Inactive
@allanlasser
Copy link
Copy Markdown
Member Author

allanlasser commented May 5, 2026

@duckduckgrayduck Take another look here? SQL optimization isn't my strong suit, so any advice here is welcome.

@duckduckgrayduck duckduckgrayduck temporarily deployed to squarelet-pi-claude-fil-lkcpjb May 6, 2026 17:18 Inactive
return queryset
if value == "none":
return queryset.filter(subscriptions__isnull=True)
return queryset.filter(subscriptions__plan_id=value)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This does the same thing as the subquery but is both more performant and much clearer to read

)
plan_value = request.GET.get("plan")
if plan_value and plan_value != "none":
qs = qs.prefetch_related(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Doing a prefetch is again more perofrmant and clearer

subs = getattr(obj, "plan_subscriptions", None)
if subs is None:
return None
return not any(s.cancelled for s in subs)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We need to check for cancelled here since it was moved out of the query

def get_subscription_renews(self, obj):
subs = getattr(obj, "plan_subscriptions", None)
if subs is None:
return None
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since this is marked as a boolean, returning a string will render it as a green check. None will render empty.

return not any(s.cancelled for s in subs)

get_subscription_renews.short_description = "Will Renew"
get_subscription_renews.boolean = True
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We lose the ability to order by cancellations, but this seems like an acceptable trade off for the performance implications

@allanlasser
Copy link
Copy Markdown
Member Author

@mitchelljkotler thanks for the optimizations here! They all make sense. Think this is ready to go on Monday?

@duckduckgrayduck duckduckgrayduck temporarily deployed to squarelet-pi-claude-fil-r8cqwd May 11, 2026 15:09 Inactive
@allanlasser allanlasser merged commit 1e8cfba into master May 12, 2026
6 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.

4 participants