Add PlanFilter to Organization admin#659
Conversation
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
|
Seems to work well- I do feel though that this would be greatly improved if we could mark who is currently subscribed vs. cancelled |
|
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. |
|
Now when filtering by a plan, a column's added to indicate whether the subscription will renew. |
c2334d7 to
76f1274
Compare
|
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 |
|
@duckduckgrayduck Take another look here? SQL optimization isn't my strong suit, so any advice here is welcome. |
| return queryset | ||
| if value == "none": | ||
| return queryset.filter(subscriptions__isnull=True) | ||
| return queryset.filter(subscriptions__plan_id=value) |
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
We lose the ability to order by cancellations, but this seems like an acceptable trade off for the performance implications
|
@mitchelljkotler thanks for the optimizations here! They all make sense. Think this is ready to go on Monday? |
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