Filtering & Sorting
Add powerful filtering and sorting capabilities to your CRUD views with automatic form generation and HTMX integration.
Basic Filtering Setup
Simple Filtering
Enable filtering by specifying which fields should be filterable:
class ProjectCRUDView(PowerCRUDMixin, CRUDView):
model = models.Project
base_template_path = "core/base.html"
fields = ["name", "owner", "status", "created_date"]
# Enable filtering on specific fields
filterset_fields = ["owner", "status", "created_date"]
This automatically generates filter forms with appropriate widgets:
- Foreign Key fields: Dropdown selection
- Choice fields: Dropdown selection
- Date fields: Date input widgets
- Text fields: Text input for contains/icontains lookup
HTMX Integration
When use_htmx = True
, filters update results reactively without page reloads:
class ProjectCRUDView(PowerCRUDMixin, CRUDView):
model = models.Project
base_template_path = "core/base.html"
use_htmx = True
filterset_fields = ["owner", "status", "created_date"]
Custom Filterset Class
For advanced filtering, provide your own filterset class:
import django_filters
from powercrud.mixins import HTMXFilterSetMixin
class ProjectFilterSet(HTMXFilterSetMixin, django_filters.FilterSet):
class Meta:
model = models.Project
fields = ["owner", "status", "created_date"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Setup HTMX attributes for reactive filtering
self.setup_htmx_attrs()
class ProjectCRUDView(PowerCRUDMixin, CRUDView):
model = models.Project
base_template_path = "core/base.html"
filterset_class = ProjectFilterSet
use_htmx = True
Table Sorting
Tables support clickable column headers for sorting:
Basic Usage
Sorting is enabled by default for all displayed fields:
class ProjectCRUDView(PowerCRUDMixin, CRUDView):
model = models.Project
base_template_path = "core/base.html"
fields = ["name", "owner", "status", "created_date"]
use_htmx = True # For reactive sorting without page reloads
Sorting Behavior
- Click any column header to sort by that field
- Click again to reverse sort direction
- Unsorted by default - first click sorts ascending
- Secondary sort by primary key ensures stable pagination
- Visual indicators show current sort direction using Hero Icons
URL Parameters
Sorting uses URL parameters that can be bookmarked:
- ?sort=name
- Sort by name (ascending)
- ?sort=-name
- Sort by name (descending)
Advanced Filtering Options
Filter Queryset Options
Restrict which options appear in filter dropdowns:
class ProjectCRUDView(PowerCRUDMixin, CRUDView):
model = models.Project
base_template_path = "core/base.html"
filterset_fields = ["owner", "status", "category"]
filter_queryset_options = {
# Only show specific owner in dropdown
'owner': {'name': 'Nancy Wilson'},
# Only show categories containing "urgent"
'category': {'name__icontains': 'urgent'},
# Only show active statuses
'status': {'is_active': True},
}
Filter Sort Options
Foreign Key Fields Only
This only affects foreign key fields with dropdown options. Other field types will ignore sort options without error.
Control how dropdown options are sorted for foreign key fields:
class ProjectCRUDView(PowerCRUDMixin, CRUDView):
model = models.Project
base_template_path = "core/base.html"
filterset_fields = ["owner", "category", "priority"]
filter_sort_options = {
'owner': 'name', # Sort owners by name (ascending)
'category': '-name', # Sort categories by name (descending)
'priority': '-order', # Sort priorities by order field (descending)
}
Many-to-Many Filter Logic
Control M2M filter logic. The default logic is AND
(all selected options must match); this can be overridden to use OR
logic (any selected option must match).
class BookCRUDView(PowerCRUDMixin, CRUDView):
model = models.Book
base_template_path = "core/base.html"
filterset_fields = ["authors", "genres"]
# Use AND logic for M2M filters (default is OR)
m2m_filter_and_logic = True
Customization & Overrides
Restricting Filter Options
Override get_filter_queryset_for_field()
to restrict available options for specific filter fields:
class ProjectCRUDView(PowerCRUDMixin, CRUDView):
model = models.Project
base_template_path = "core/base.html"
filterset_fields = ["owner", "status"]
def get_queryset(self):
"""Restrict main queryset to current user's projects."""
qs = super().get_queryset()
return qs.filter(owner=self.request.user)
def get_filter_queryset_for_field(self, field_name, model_field):
"""Restrict filter options to match main queryset restrictions."""
qs = super().get_filter_queryset_for_field(field_name, model_field)
if field_name == 'owner':
# Only show current user in owner dropdown
qs = qs.filter(id=self.request.user.id)
elif field_name == 'category':
# Only show categories used by current user's projects
qs = qs.filter(projects__owner=self.request.user).distinct()
return qs
Method Parameters:
field_name
(str): The name of the field being filteredmodel_field
: The actual Django model field instance (e.g., ForeignKey, CharField)
Complete Examples
class ProjectCRUDView(PowerCRUDMixin, CRUDView):
model = models.Project
base_template_path = "core/base.html"
fields = ["name", "owner", "status", "created_date"]
# Enable filtering and sorting
filterset_fields = ["owner", "status", "created_date"]
use_htmx = True
# Customize filter options
filter_sort_options = {
'owner': 'name',
'status': 'priority',
}
class BookCRUDView(PowerCRUDMixin, CRUDView):
model = models.Book
base_template_path = "core/base.html"
fields = ["title", "author", "genres", "published_date"]
# Advanced filtering setup
filterset_fields = ["author", "genres", "published_date"]
use_htmx = True
# M2M filter with AND logic
m2m_filter_and_logic = True
# Restrict and sort filter options
filter_queryset_options = {
'author': {'is_active': True},
'genres': {'name__icontains': 'fiction'},
}
filter_sort_options = {
'author': 'name',
'genres': '-popularity',
}
def get_filter_queryset_for_field(self, field_name, model_field):
"""Further restrict filter options based on user permissions."""
qs = super().get_filter_queryset_for_field(field_name, model_field)
if field_name == 'author' and not self.request.user.is_staff:
# Non-staff users only see public authors
qs = qs.filter(is_public=True)
return qs
import django_filters
from powercrud.mixins import HTMXFilterSetMixin
class ProjectFilterSet(HTMXFilterSetMixin, django_filters.FilterSet):
# Custom filter with choices
priority = django_filters.ChoiceFilter(
choices=[('high', 'High'), ('medium', 'Medium'), ('low', 'Low')],
empty_label="Any Priority"
)
# Date range filter
created_date = django_filters.DateRangeFilter()
class Meta:
model = models.Project
fields = ["owner", "status", "priority", "created_date"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Setup HTMX attributes for reactive filtering
self.setup_htmx_attrs()
class ProjectCRUDView(PowerCRUDMixin, CRUDView):
model = models.Project
base_template_path = "core/base.html"
filterset_class = ProjectFilterSet
use_htmx = True