CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-django-braces

Reusable, generic mixins for Django class-based views

Pending
Overview
Eval results
Files

query-optimization.mddocs/

Database Query Optimization

Mixins for optimizing database queries in Django class-based views through select_related, prefetch_related, and dynamic ordering. These mixins help reduce database queries and improve performance in list and detail views.

Capabilities

Select Related Optimization

Automatically apply select_related to reduce database queries for foreign key relationships.

class SelectRelatedMixin:
    """Automatically apply select_related for list of relations"""
    select_related = None
    
    def get_queryset(self):
        """Apply select_related with appropriate fields to queryset"""

Usage example:

from django.views.generic import ListView
from braces.views import SelectRelatedMixin

class OptimizedPostListView(SelectRelatedMixin, ListView):
    model = Post
    select_related = ['author', 'category', 'author__profile']
    
    # This will generate:
    # Post.objects.select_related('author', 'category', 'author__profile')

Performance comparison:

# Without SelectRelatedMixin - N+1 queries
class SlowPostListView(ListView):
    model = Post
    # Template access to {{ post.author.name }} causes additional query per post

# With SelectRelatedMixin - Single query
class FastPostListView(SelectRelatedMixin, ListView):
    model = Post
    select_related = ['author', 'category']
    # All related data fetched in one query

Prefetch Related Optimization

Automatically apply prefetch_related for many-to-many and reverse foreign key relationships.

class PrefetchRelatedMixin:
    """Automatically apply prefetch_related for list of relations"""
    prefetch_related = None
    
    def get_queryset(self):
        """Apply prefetch_related with appropriate fields to queryset"""

Usage example:

from django.views.generic import ListView
from braces.views import PrefetchRelatedMixin

class TaggedPostListView(PrefetchRelatedMixin, ListView):
    model = Post
    prefetch_related = ['tags', 'comments', 'comments__author']
    
    # This will generate:
    # Post.objects.prefetch_related('tags', 'comments', 'comments__author')

Complex prefetching with Prefetch objects:

from django.db.models import Prefetch
from django.views.generic import ListView
from braces.views import PrefetchRelatedMixin

class AdvancedPostListView(PrefetchRelatedMixin, ListView):
    model = Post
    
    def get_queryset(self):
        # Custom prefetch with filtering
        active_comments = Prefetch(
            'comments',
            queryset=Comment.objects.filter(is_active=True).select_related('author')
        )
        
        return super().get_queryset().prefetch_related(
            active_comments,
            'tags',
            'author__groups'
        )

Dynamic List Ordering

Enable URL-based sorting for list views with validation and defaults.

class OrderableListMixin:
    """Order queryset based on GET parameters"""
    orderable_columns = None
    orderable_columns_default = None
    ordering_default = None
    order_by = None
    ordering = None
    
    def get_context_data(self, **kwargs):
        """Augment context with order_by and ordering"""
        
    def get_orderable_columns(self):
        """Check that orderable columns are set and return them"""
        
    def get_orderable_columns_default(self):
        """Which column(s) should be sorted by default"""
        
    def get_ordering_default(self):
        """Which direction should things be sorted"""
        
    def get_ordered_queryset(self, queryset=None):
        """Augment QuerySet with order_by statement if possible"""
        
    def get_queryset(self):
        """Returns ordered QuerySet"""

Usage example:

from django.views.generic import ListView
from braces.views import OrderableListMixin

class SortablePostListView(OrderableListMixin, ListView):
    model = Post
    orderable_columns = ['title', 'created', 'author__username', 'category__name']
    orderable_columns_default = 'created'
    ordering_default = 'desc'
    
    # URLs:
    # /posts/ - Default: ordered by created desc
    # /posts/?order_by=title&ordering=asc - Title ascending
    # /posts/?order_by=author__username - Author username desc (default)

Template usage:

<!-- Template: post_list.html -->
<table>
    <thead>
        <tr>
            <th>
                <a href="?order_by=title&ordering={% if order_by == 'title' and ordering == 'asc' %}desc{% else %}asc{% endif %}">
                    Title
                    {% if order_by == 'title' %}
                        {% if ordering == 'asc' %}↑{% else %}↓{% endif %}
                    {% endif %}
                </a>
            </th>
            <th>
                <a href="?order_by=created&ordering={% if order_by == 'created' and ordering == 'asc' %}desc{% else %}asc{% endif %}">
                    Created
                    {% if order_by == 'created' %}
                        {% if ordering == 'asc' %}↑{% else %}↓{% endif %}
                    {% endif %}
                </a>
            </th>
        </tr>
    </thead>
    <tbody>
        {% for post in object_list %}
        <tr>
            <td>{{ post.title }}</td>
            <td>{{ post.created }}</td>
        </tr>
        {% endfor %}
    </tbody>
</table>

Common Usage Patterns

Combined Query Optimization

Combine select_related and prefetch_related for maximum efficiency:

from django.views.generic import ListView
from braces.views import SelectRelatedMixin, PrefetchRelatedMixin

class FullyOptimizedListView(SelectRelatedMixin, PrefetchRelatedMixin, ListView):
    model = Post
    select_related = ['author', 'category']  # Foreign keys
    prefetch_related = ['tags', 'comments']  # Many-to-many and reverse FKs

Sortable Optimized Lists

Combine ordering with query optimization:

from django.views.generic import ListView
from braces.views import SelectRelatedMixin, OrderableListMixin

class SortableOptimizedListView(SelectRelatedMixin, OrderableListMixin, ListView):
    model = Post
    select_related = ['author', 'category']
    orderable_columns = ['title', 'created', 'author__username', 'category__name']
    orderable_columns_default = 'created'
    ordering_default = 'desc'

Advanced Query Optimization

Custom queryset modifications with optimization mixins:

from django.views.generic import ListView
from braces.views import SelectRelatedMixin, PrefetchRelatedMixin
from django.db.models import Count, Prefetch

class AdvancedOptimizedListView(SelectRelatedMixin, PrefetchRelatedMixin, ListView):
    model = Post
    select_related = ['author', 'category']
    
    def get_queryset(self):
        # Get base optimized queryset
        queryset = super().get_queryset()
        
        # Add annotations
        queryset = queryset.annotate(
            comment_count=Count('comments'),
            tag_count=Count('tags')
        )
        
        # Add custom prefetch
        active_comments = Prefetch(
            'comments',
            queryset=Comment.objects.filter(is_active=True).order_by('-created')
        )
        
        return queryset.prefetch_related(active_comments)
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Additional context using optimized queries
        context['total_posts'] = self.get_queryset().count()
        context['categories'] = Category.objects.annotate(
            post_count=Count('posts')
        ).order_by('name')
        
        return context

Performance Monitoring

Track query performance with debugging:

import logging
from django.views.generic import ListView
from braces.views import SelectRelatedMixin, PrefetchRelatedMixin
from django.db import connection

logger = logging.getLogger(__name__)

class MonitoredOptimizedListView(SelectRelatedMixin, PrefetchRelatedMixin, ListView):
    model = Post
    select_related = ['author', 'category']
    prefetch_related = ['tags']
    
    def get_queryset(self):
        initial_queries = len(connection.queries)
        queryset = super().get_queryset()
        
        if settings.DEBUG:
            query_count = len(connection.queries) - initial_queries
            logger.info(f"Queryset generation used {query_count} queries")
            
        return queryset
    
    def get_context_data(self, **kwargs):
        initial_queries = len(connection.queries)
        context = super().get_context_data(**kwargs)
        
        if settings.DEBUG:
            query_count = len(connection.queries) - initial_queries
            logger.info(f"Context generation used {query_count} queries")
            
        return context

Conditional Optimization

Apply different optimizations based on context:

from django.views.generic import ListView
from braces.views import SelectRelatedMixin, PrefetchRelatedMixin, OrderableListMixin

class ConditionalOptimizedListView(
    SelectRelatedMixin, 
    PrefetchRelatedMixin, 
    OrderableListMixin, 
    ListView
):
    model = Post
    orderable_columns = ['title', 'created', 'author__username']
    orderable_columns_default = 'created'
    
    def get_select_related(self):
        # Always optimize author
        relations = ['author']
        
        # Add category if sorting by it
        if self.request.GET.get('order_by', '').startswith('category'):
            relations.append('category')
            
        return relations
    
    def get_prefetch_related(self):
        relations = []
        
        # Only prefetch tags if user wants to see them
        if self.request.GET.get('show_tags'):
            relations.append('tags')
            
        # Prefetch comments for staff users
        if self.request.user.is_staff:
            relations.append('comments')
            
        return relations
    
    def get_queryset(self):
        # Set dynamic relations
        self.select_related = self.get_select_related()
        self.prefetch_related = self.get_prefetch_related()
        
        return super().get_queryset()

Install with Tessl CLI

npx tessl i tessl/pypi-django-braces

docs

access-control.md

ajax-json.md

form-processing.md

http-utilities.md

index.md

query-optimization.md

tile.json