Saved Favourites
Saved favourites are an optional add-on for teams that want named, reusable list states per user.
This feature is intentionally shipped as a contrib app so projects that do not need it do not have to carry its model, migration, or UI surface.
Use this guide when you want to:
- install the favourites contrib app
- enable it on selected list views
- understand what the saved state includes
- understand how it behaves when the app is not installed
What it saves
PowerCRUD can persist named list states per authenticated user, including:
- active filter values
- optional filter visibility
- current sort
- current page size
- visible columns when the list view opts into list options
The saved payload intentionally does not persist the current page number.
Installation
Add the contrib app to INSTALLED_APPS:
Then run migrations:
Mount the shared PowerCRUD URLs with the powercrud namespace:
# urls.py
from django.urls import include, path
urlpatterns = [
# ...
path("powercrud/", include("powercrud.urls", namespace="powercrud")),
]
The URL prefix can be different, but the namespace must stay powercrud.
These setup steps are optional. If you never install the contrib app, the rest of PowerCRUD filtering still works normally.
Enable it on a list view
That turns on the favourites toolbar for that list view, provided the contrib app is installed and the shared PowerCRUD URLs are mounted.
Scoping
Saved favourites are scoped per:
- authenticated user
- list view identity
The view identity is derived automatically from "<module>.<ClassName>".
Ownership resolver
By default, PowerCRUD stores and reads favourites for request.user.
If you do not configure anything else, the current authenticated Django user owns every saved favourite.
Projects that need a different owner for saved favourites can configure a resolver in POWERCRUD_SETTINGS:
POWERCRUD_SETTINGS = {
"FILTER_FAVOURITE_USER_RESOLVER": "myapp.powercrud.resolve_filter_favourite_user",
}
The resolver receives the current request and returns the user whose favourites should be listed, created, updated, applied, and deleted:
# myapp/powercrud.py
def resolve_filter_favourite_user(request):
"""Return the user who should own saved PowerCRUD filter favourites."""
return getattr(request, "original_operator", None) or request.user
A session-backed resolver can also look up the owner explicitly:
# myapp/powercrud.py
from django.contrib.auth import get_user_model
def resolve_filter_favourite_user(request):
"""Return the user who should own saved PowerCRUD filter favourites."""
user_id = request.session.get("original_operator_user_id")
if not user_id:
return request.user
return get_user_model().objects.get(pk=user_id)
This setting exists because the save, apply, update, and delete endpoints are shared PowerCRUD function views. Those endpoints receive the HTTP request, but not the original CRUDView instance that rendered the list. The setting gives those shared endpoints the same owner decision as the toolbar/list render path.
List views can also override get_filter_favourite_user(request) when only the initial list-render context needs custom ownership.
For end-to-end custom ownership, prefer FILTER_FAVOURITE_USER_RESOLVER so the shared favourites endpoints use the same owner.
Changing the resolver does not change the database shape.
Favourites remain keyed by user + view_key + name.
If an existing deployment changes from request.user ownership to another owner, any migration or copy of existing saved favourites is a downstream data decision.
Behavior notes
- Anonymous users still see the toolbar when the view enables favourites, but the save, update, and delete controls remain unavailable and the UI prompts them to sign in.
- Applying a saved favourite restores the saved filters, optional filter visibility, sort, page size, and visible columns.
- Applying a saved favourite does not restore whether the filter panel was open. Returning to a list starts with the filter panel closed, and the filter toggle indicates when active filter values are present.
- Toolbar icons use a shared active-state convention: a filled primary heart means a clean saved favourite is selected, a warning-coloured heart means that favourite has unsaved edits, and a filled primary funnel means filters are currently applied.
- Unsaved list experiments are not restored after navigation. Temporary filters, optional filter visibility, sort, page size, and pagination should be saved as a favourite when they need to be reusable.
- Applying an older saved favourite without visible-column state resets visible columns to the view's
default_list_fields, or to every allowed column when no default subset is declared. - The current UI is intentionally compact:
- selecting a saved favourite auto-applies it
- the selected-favourite trigger stays visible when the filter panel is closed
- long selected favourite names are truncated in the trigger and exposed through a tooltip
Availability guard
If a developer sets filter_favourites_enabled = True on a view but either:
- does not install
powercrud.contrib.favourites - or does not mount the shared
powercrudURLs
PowerCRUD silently disables the feature at runtime.
That means:
- no toolbar renders
- no favourites URLs are included
- no broken
Noneendpoint values appear in the rendered HTML - Django emits a system check warning when the contrib app is installed but the shared
powercrudURLs are missing
PowerCRUD detects this from both:
apps.is_installed("powercrud.contrib.favourites")- successful reversing of the required
powercrud:favourites-*routes
Sample app
The sample BookCRUDView demonstrates the feature end-to-end and is the best reference implementation in the demo project.
For the broader filtering story that favourites build on top of, see Filtering. For column visibility behavior, see List Options.