Authentication and Authorization

Authorization in Views and Templates

Implementing proper authorization in Django views and templates ensures that users can only access resources and perform actions they're permitted to. Understanding how to apply authorization at different levels - from view-level access control to fine-grained template permissions - is crucial for building secure applications.

Authorization in Views and Templates

Implementing proper authorization in Django views and templates ensures that users can only access resources and perform actions they're permitted to. Understanding how to apply authorization at different levels - from view-level access control to fine-grained template permissions - is crucial for building secure applications.

View-Level Authorization

Function-Based View Authorization

# Authorization in function-based views
from django.contrib.auth.decorators import login_required, permission_required, user_passes_test
from django.core.exceptions import PermissionDenied
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib import messages

# Basic login requirement
@login_required
def profile_view(request):
    """View requiring user to be logged in"""
    
    return render(request, 'profile.html', {
        'user': request.user
    })

# Permission-based authorization
@login_required
@permission_required('blog.add_post', raise_exception=True)
def create_post_view(request):
    """View requiring specific permission"""
    
    if request.method == 'POST':
        # User has permission to create posts
        form = PostForm(request.POST)
        
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()
            
            messages.success(request, 'Post created successfully!')
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    
    return render(request, 'create_post.html', {'form': form})

# Multiple permissions
@login_required
@permission_required(['blog.change_post', 'blog.can_publish'], raise_exception=True)
def publish_post_view(request, post_id):
    """View requiring multiple permissions"""
    
    post = get_object_or_404(Post, pk=post_id)
    
    # Additional authorization logic
    if not can_user_publish_post(request.user, post):
        raise PermissionDenied("You cannot publish this post.")
    
    post.status = 'published'
    post.published_at = timezone.now()
    post.save()
    
    messages.success(request, 'Post published successfully!')
    return redirect('post_detail', pk=post.pk)

def can_user_publish_post(user, post):
    """Custom authorization logic for publishing posts"""
    
    # Authors can publish their own posts
    if post.author == user:
        return True
    
    # Editors can publish any post
    if user.groups.filter(name='Editors').exists():
        return True
    
    # Publishers can publish any post
    if user.has_perm('blog.can_publish'):
        return True
    
    return False

# Custom user test
def is_author_or_editor(user):
    """Check if user is author or editor"""
    
    if not user.is_authenticated:
        return False
    
    return (user.groups.filter(name__in=['Authors', 'Editors']).exists() or
            user.has_perm('blog.add_post'))

@user_passes_test(is_author_or_editor, login_url='login')
def author_dashboard_view(request):
    """View for authors and editors only"""
    
    user_posts = Post.objects.filter(author=request.user)
    
    context = {
        'posts': user_posts,
        'can_publish': request.user.has_perm('blog.can_publish'),
        'is_editor': request.user.groups.filter(name='Editors').exists(),
    }
    
    return render(request, 'author_dashboard.html', context)

# Object-level authorization
@login_required
def edit_post_view(request, post_id):
    """View with object-level authorization"""
    
    post = get_object_or_404(Post, pk=post_id)
    
    # Check if user can edit this specific post
    if not can_user_edit_post(request.user, post):
        messages.error(request, "You don't have permission to edit this post.")
        return redirect('post_detail', pk=post.pk)
    
    if request.method == 'POST':
        form = PostForm(request.POST, instance=post)
        
        if form.is_valid():
            form.save()
            messages.success(request, 'Post updated successfully!')
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post)
    
    return render(request, 'edit_post.html', {
        'form': form,
        'post': post
    })

def can_user_edit_post(user, post):
    """Check if user can edit specific post"""
    
    # Superusers can edit anything
    if user.is_superuser:
        return True
    
    # Authors can edit their own posts
    if post.author == user:
        return True
    
    # Editors can edit any post
    if user.groups.filter(name='Editors').exists():
        return True
    
    # Users with change permission can edit
    if user.has_perm('blog.change_post'):
        return True
    
    return False

# Advanced authorization with custom decorators
def require_ownership_or_permission(model, permission, pk_field='pk'):
    """Decorator requiring object ownership or specific permission"""
    
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if not request.user.is_authenticated:
                return redirect('login')
            
            # Get object
            obj_pk = kwargs.get(pk_field)
            obj = get_object_or_404(model, pk=obj_pk)
            
            # Check ownership or permission
            has_permission = (
                getattr(obj, 'author', None) == request.user or
                request.user.has_perm(permission) or
                request.user.is_superuser
            )
            
            if not has_permission:
                raise PermissionDenied("You don't have permission to access this resource.")
            
            # Add object to kwargs for convenience
            kwargs['object'] = obj
            
            return view_func(request, *args, **kwargs)
        
        return wrapper
    return decorator

@require_ownership_or_permission(Post, 'blog.change_post', 'post_id')
def advanced_edit_post_view(request, post_id, object=None):
    """View using custom authorization decorator"""
    
    post = object  # Provided by decorator
    
    # Rest of the view logic...
    return render(request, 'edit_post.html', {'post': post})

Class-Based View Authorization

# Authorization in class-based views
from django.contrib.auth.mixins import (
    LoginRequiredMixin, PermissionRequiredMixin, UserPassesTestMixin
)
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView

class AuthorizedListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
    """List view with permission requirements"""
    
    model = Post
    template_name = 'post_list.html'
    permission_required = 'blog.view_post'
    
    def get_queryset(self):
        """Filter queryset based on user permissions"""
        
        queryset = super().get_queryset()
        
        # Superusers see everything
        if self.request.user.is_superuser:
            return queryset
        
        # Editors see all posts
        if self.request.user.groups.filter(name='Editors').exists():
            return queryset
        
        # Authors see only their own posts and published posts
        if self.request.user.groups.filter(name='Authors').exists():
            return queryset.filter(
                Q(author=self.request.user) | Q(status='published')
            )
        
        # Regular users see only published posts
        return queryset.filter(status='published')

class PostCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
    """Create view with permission requirements"""
    
    model = Post
    form_class = PostForm
    template_name = 'create_post.html'
    permission_required = 'blog.add_post'
    
    def form_valid(self, form):
        """Set author when form is valid"""
        
        form.instance.author = self.request.user
        
        # Check if user can set status to published
        if form.instance.status == 'published':
            if not self.request.user.has_perm('blog.can_publish'):
                form.instance.status = 'draft'
                messages.warning(
                    self.request,
                    'Post saved as draft. You need publish permission to publish directly.'
                )
        
        return super().form_valid(form)

class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    """Update view with custom authorization test"""
    
    model = Post
    form_class = PostForm
    template_name = 'edit_post.html'
    
    def test_func(self):
        """Test if user can edit this post"""
        
        post = self.get_object()
        return can_user_edit_post(self.request.user, post)
    
    def handle_no_permission(self):
        """Handle when user doesn't have permission"""
        
        messages.error(
            self.request,
            "You don't have permission to edit this post."
        )
        return redirect('post_detail', pk=self.get_object().pk)

class PostDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    """Delete view with ownership check"""
    
    model = Post
    template_name = 'delete_post.html'
    success_url = reverse_lazy('post_list')
    
    def test_func(self):
        """Test if user can delete this post"""
        
        post = self.get_object()
        user = self.request.user
        
        # Only author or users with delete permission can delete
        return (
            post.author == user or
            user.has_perm('blog.delete_post') or
            user.is_superuser
        )

# Custom authorization mixins
class OwnerRequiredMixin(UserPassesTestMixin):
    """Mixin requiring user to be owner of object"""
    
    owner_field = 'author'
    
    def test_func(self):
        """Test if user owns the object"""
        
        obj = self.get_object()
        owner = getattr(obj, self.owner_field, None)
        
        return (
            owner == self.request.user or
            self.request.user.is_superuser
        )

class GroupRequiredMixin(UserPassesTestMixin):
    """Mixin requiring user to be in specific groups"""
    
    required_groups = []
    
    def test_func(self):
        """Test if user is in required groups"""
        
        if not self.request.user.is_authenticated:
            return False
        
        if self.request.user.is_superuser:
            return True
        
        user_groups = self.request.user.groups.values_list('name', flat=True)
        
        return any(group in user_groups for group in self.required_groups)

class ConditionalPermissionMixin:
    """Mixin for conditional permission checking"""
    
    def dispatch(self, request, *args, **kwargs):
        """Check permissions before dispatching"""
        
        if not self.check_permissions(request):
            return self.handle_no_permission()
        
        return super().dispatch(request, *args, **kwargs)
    
    def check_permissions(self, request):
        """Override this method to implement custom permission logic"""
        
        return True
    
    def handle_no_permission(self):
        """Handle permission denied"""
        
        raise PermissionDenied("Access denied")

# Usage examples of custom mixins
class MyPostsView(LoginRequiredMixin, OwnerRequiredMixin, ListView):
    """View showing user's own posts"""
    
    model = Post
    template_name = 'my_posts.html'
    owner_field = 'author'
    
    def get_queryset(self):
        return Post.objects.filter(author=self.request.user)

class EditorOnlyView(LoginRequiredMixin, GroupRequiredMixin, TemplateView):
    """View for editors only"""
    
    template_name = 'editor_panel.html'
    required_groups = ['Editors', 'Administrators']

class BusinessHoursView(LoginRequiredMixin, ConditionalPermissionMixin, TemplateView):
    """View accessible only during business hours"""
    
    template_name = 'business_view.html'
    
    def check_permissions(self, request):
        """Allow access only during business hours"""
        
        current_hour = timezone.now().hour
        
        # Business hours: 9 AM to 5 PM
        if 9 <= current_hour <= 17:
            return True
        
        # Superusers can access anytime
        if request.user.is_superuser:
            return True
        
        return False
    
    def handle_no_permission(self):
        """Custom handling for business hours restriction"""
        
        messages.warning(
            self.request,
            'This feature is only available during business hours (9 AM - 5 PM).'
        )
        return redirect('dashboard')

Template Authorization

Template Permission Checks

# Template context processors for authorization
def auth_context_processor(request):
    """Add authorization context to templates"""
    
    context = {}
    
    if request.user.is_authenticated:
        context.update({
            'user_permissions': request.user.get_all_permissions(),
            'user_groups': request.user.groups.values_list('name', flat=True),
            'is_staff': request.user.is_staff,
            'is_superuser': request.user.is_superuser,
        })
        
        # Add convenience permission checks
        context.update({
            'can_add_post': request.user.has_perm('blog.add_post'),
            'can_change_post': request.user.has_perm('blog.change_post'),
            'can_delete_post': request.user.has_perm('blog.delete_post'),
            'can_publish_post': request.user.has_perm('blog.can_publish'),
            'is_editor': request.user.groups.filter(name='Editors').exists(),
            'is_author': request.user.groups.filter(name='Authors').exists(),
        })
    
    return context

# Custom template tags for authorization
from django import template
from django.contrib.auth.models import Group

register = template.Library()

@register.simple_tag(takes_context=True)
def user_has_perm(context, permission, obj=None):
    """Check if user has specific permission"""
    
    user = context['request'].user
    
    if not user.is_authenticated:
        return False
    
    return user.has_perm(permission, obj)

@register.simple_tag(takes_context=True)
def user_in_group(context, group_name):
    """Check if user is in specific group"""
    
    user = context['request'].user
    
    if not user.is_authenticated:
        return False
    
    return user.groups.filter(name=group_name).exists()

@register.simple_tag(takes_context=True)
def user_can_edit_object(context, obj):
    """Check if user can edit specific object"""
    
    user = context['request'].user
    
    if not user.is_authenticated:
        return False
    
    # Check ownership
    if hasattr(obj, 'author') and obj.author == user:
        return True
    
    # Check permissions
    model_name = obj._meta.model_name
    app_label = obj._meta.app_label
    
    return user.has_perm(f'{app_label}.change_{model_name}')

@register.inclusion_tag('auth/permission_menu.html', takes_context=True)
def permission_menu(context):
    """Render permission-based menu"""
    
    user = context['request'].user
    
    menu_items = []
    
    if user.is_authenticated:
        # Dashboard (always available)
        menu_items.append({
            'title': 'Dashboard',
            'url': 'dashboard',
            'icon': 'dashboard'
        })
        
        # Content management
        if user.has_perm('blog.add_post'):
            menu_items.append({
                'title': 'Create Post',
                'url': 'create_post',
                'icon': 'add'
            })
        
        if user.has_perm('blog.view_post'):
            menu_items.append({
                'title': 'My Posts',
                'url': 'my_posts',
                'icon': 'list'
            })
        
        # Admin functions
        if user.groups.filter(name='Editors').exists():
            menu_items.append({
                'title': 'Editor Panel',
                'url': 'editor_panel',
                'icon': 'edit'
            })
        
        if user.is_staff:
            menu_items.append({
                'title': 'Admin',
                'url': 'admin:index',
                'icon': 'admin'
            })
    
    return {'menu_items': menu_items}

@register.filter
def can_perform_action(user, action_object_pair):
    """Filter to check if user can perform action on object"""
    
    try:
        action, obj = action_object_pair.split(':', 1)
        
        if action == 'edit':
            return user_can_edit_object({'request': type('obj', (), {'user': user})()}, obj)
        elif action == 'delete':
            return user.has_perm(f'{obj._meta.app_label}.delete_{obj._meta.model_name}')
        elif action == 'view':
            return user.has_perm(f'{obj._meta.app_label}.view_{obj._meta.model_name}')
        
    except (ValueError, AttributeError):
        pass
    
    return False

Template Examples

<!-- Template authorization examples -->

<!-- Basic permission checks -->
{% load auth_tags %}

<!-- Check if user is authenticated -->
{% if user.is_authenticated %}
    <p>Welcome, {{ user.get_full_name|default:user.username }}!</p>
    
    <!-- Check specific permission -->
    {% if user|user_has_perm:"blog.add_post" %}
        <a href="{% url 'create_post' %}" class="btn btn-primary">Create Post</a>
    {% endif %}
    
    <!-- Check group membership -->
    {% if user|user_in_group:"Editors" %}
        <a href="{% url 'editor_panel' %}" class="btn btn-secondary">Editor Panel</a>
    {% endif %}
    
    <!-- Check multiple conditions -->
    {% if user.is_staff or user|user_in_group:"Moderators" %}
        <div class="admin-tools">
            <h3>Admin Tools</h3>
            <!-- Admin content -->
        </div>
    {% endif %}
{% else %}
    <a href="{% url 'login' %}" class="btn btn-primary">Login</a>
    <a href="{% url 'register' %}" class="btn btn-secondary">Register</a>
{% endif %}

<!-- Object-level permissions -->
{% for post in posts %}
    <div class="post">
        <h3>{{ post.title }}</h3>
        <p>{{ post.content|truncatewords:50 }}</p>
        
        <div class="post-actions">
            <!-- View link (always available for published posts) -->
            <a href="{% url 'post_detail' post.pk %}">View</a>
            
            <!-- Edit link (only for authorized users) -->
            {% if user|user_can_edit_object:post %}
                <a href="{% url 'edit_post' post.pk %}">Edit</a>
            {% endif %}
            
            <!-- Delete link (only for authorized users) -->
            {% if user.has_perm:"blog.delete_post" or post.author == user %}
                <a href="{% url 'delete_post' post.pk %}" 
                   onclick="return confirm('Are you sure?')">Delete</a>
            {% endif %}
            
            <!-- Publish link (only for users with publish permission) -->
            {% if post.status == 'draft' and user.has_perm:"blog.can_publish" %}
                <a href="{% url 'publish_post' post.pk %}">Publish</a>
            {% endif %}
        </div>
    </div>
{% endfor %}

<!-- Conditional content based on permissions -->
<div class="sidebar">
    {% if user.is_authenticated %}
        <!-- User menu -->
        {% permission_menu %}
        
        <!-- User stats (only for authors and editors) -->
        {% if user|user_in_group:"Authors" or user|user_in_group:"Editors" %}
            <div class="user-stats">
                <h4>Your Statistics</h4>
                <p>Posts: {{ user.posts.count }}</p>
                <p>Published: {{ user.posts.published.count }}</p>
                <p>Drafts: {{ user.posts.drafts.count }}</p>
            </div>
        {% endif %}
        
        <!-- Admin quick links -->
        {% if user.is_staff %}
            <div class="admin-links">
                <h4>Admin Quick Links</h4>
                <ul>
                    <li><a href="{% url 'admin:auth_user_changelist' %}">Users</a></li>
                    <li><a href="{% url 'admin:blog_post_changelist' %}">Posts</a></li>
                    <li><a href="{% url 'admin:auth_group_changelist' %}">Groups</a></li>
                </ul>
            </div>
        {% endif %}
    {% endif %}
</div>

<!-- Form with conditional fields -->
<form method="post">
    {% csrf_token %}
    
    <!-- Basic fields (available to all) -->
    {{ form.title }}
    {{ form.content }}
    
    <!-- Advanced fields (only for editors) -->
    {% if user|user_in_group:"Editors" %}
        {{ form.featured }}
        {{ form.category }}
        {{ form.tags }}
    {% endif %}
    
    <!-- Status field (conditional options) -->
    <div class="form-group">
        <label for="status">Status:</label>
        <select name="status" id="status">
            <option value="draft">Draft</option>
            {% if user.has_perm:"blog.can_publish" %}
                <option value="published">Published</option>
            {% endif %}
            {% if user|user_in_group:"Editors" %}
                <option value="featured">Featured</option>
            {% endif %}
        </select>
    </div>
    
    <button type="submit">
        {% if user.has_perm:"blog.can_publish" %}
            Save and Publish
        {% else %}
            Save as Draft
        {% endif %}
    </button>
</form>

<!-- Navigation with permission-based items -->
<nav class="navbar">
    <ul class="nav-menu">
        <li><a href="{% url 'home' %}">Home</a></li>
        
        {% if user.is_authenticated %}
            <li><a href="{% url 'dashboard' %}">Dashboard</a></li>
            
            {% if user.has_perm:"blog.view_post" %}
                <li><a href="{% url 'post_list' %}">Posts</a></li>
            {% endif %}
            
            {% if user.has_perm:"blog.add_post" %}
                <li><a href="{% url 'create_post' %}">Create</a></li>
            {% endif %}
            
            {% if user|user_in_group:"Editors" %}
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle">Editor Tools</a>
                    <ul class="dropdown-menu">
                        <li><a href="{% url 'pending_posts' %}">Pending Posts</a></li>
                        <li><a href="{% url 'featured_posts' %}">Featured Posts</a></li>
                        <li><a href="{% url 'analytics' %}">Analytics</a></li>
                    </ul>
                </li>
            {% endif %}
            
            {% if user.is_staff %}
                <li><a href="{% url 'admin:index' %}">Admin</a></li>
            {% endif %}
            
            <li class="user-menu">
                <a href="#" class="dropdown-toggle">{{ user.username }}</a>
                <ul class="dropdown-menu">
                    <li><a href="{% url 'profile' %}">Profile</a></li>
                    <li><a href="{% url 'settings' %}">Settings</a></li>
                    <li><a href="{% url 'logout' %}">Logout</a></li>
                </ul>
            </li>
        {% else %}
            <li><a href="{% url 'login' %}">Login</a></li>
            <li><a href="{% url 'register' %}">Register</a></li>
        {% endif %}
    </ul>
</nav>

Advanced Authorization Patterns

Dynamic Permission Checking

# Advanced authorization patterns
class DynamicAuthorizationMixin:
    """Mixin for dynamic authorization based on context"""
    
    def dispatch(self, request, *args, **kwargs):
        """Check dynamic permissions before dispatch"""
        
        # Get authorization context
        auth_context = self.get_authorization_context(request, *args, **kwargs)
        
        # Check permissions
        if not self.check_dynamic_permissions(request, auth_context):
            return self.handle_authorization_failure(request, auth_context)
        
        return super().dispatch(request, *args, **kwargs)
    
    def get_authorization_context(self, request, *args, **kwargs):
        """Get context for authorization decision"""
        
        context = {
            'user': request.user,
            'time': timezone.now(),
            'ip_address': request.META.get('REMOTE_ADDR'),
            'user_agent': request.META.get('HTTP_USER_AGENT'),
            'path': request.path,
            'method': request.method,
        }
        
        # Add object context if available
        if hasattr(self, 'get_object'):
            try:
                context['object'] = self.get_object()
            except:
                pass
        
        return context
    
    def check_dynamic_permissions(self, request, context):
        """Check permissions based on dynamic context"""
        
        # Time-based permissions
        if not self.check_time_based_permissions(context):
            return False
        
        # Location-based permissions
        if not self.check_location_based_permissions(context):
            return False
        
        # Object-based permissions
        if not self.check_object_based_permissions(context):
            return False
        
        # Custom business logic
        if not self.check_business_logic_permissions(context):
            return False
        
        return True
    
    def check_time_based_permissions(self, context):
        """Check time-based permission restrictions"""
        
        # Override in subclasses for specific time restrictions
        return True
    
    def check_location_based_permissions(self, context):
        """Check location-based permission restrictions"""
        
        # Override in subclasses for IP/location restrictions
        return True
    
    def check_object_based_permissions(self, context):
        """Check object-specific permissions"""
        
        # Override in subclasses for object-level checks
        return True
    
    def check_business_logic_permissions(self, context):
        """Check custom business logic permissions"""
        
        # Override in subclasses for custom logic
        return True
    
    def handle_authorization_failure(self, request, context):
        """Handle authorization failure"""
        
        raise PermissionDenied("Access denied based on current context")

# Example usage of dynamic authorization
class TimeRestrictedEditView(DynamicAuthorizationMixin, UpdateView):
    """Edit view restricted to business hours"""
    
    model = Post
    form_class = PostForm
    
    def check_time_based_permissions(self, context):
        """Allow editing only during business hours"""
        
        current_time = context['time']
        current_hour = current_time.hour
        
        # Business hours: 9 AM to 6 PM, Monday to Friday
        if current_time.weekday() >= 5:  # Weekend
            return context['user'].is_superuser
        
        if not (9 <= current_hour <= 18):  # Outside business hours
            return context['user'].is_superuser
        
        return True
    
    def check_object_based_permissions(self, context):
        """Check if user can edit this specific object"""
        
        obj = context.get('object')
        user = context['user']
        
        if not obj:
            return True
        
        # Authors can edit their own posts
        if obj.author == user:
            return True
        
        # Editors can edit any post
        if user.groups.filter(name='Editors').exists():
            return True
        
        return False

class LocationRestrictedView(DynamicAuthorizationMixin, TemplateView):
    """View restricted to specific IP ranges"""
    
    allowed_ip_ranges = ['192.168.1.0/24', '10.0.0.0/8']
    
    def check_location_based_permissions(self, context):
        """Check if request comes from allowed IP range"""
        
        import ipaddress
        
        client_ip = context['ip_address']
        
        # Superusers can access from anywhere
        if context['user'].is_superuser:
            return True
        
        # Check if IP is in allowed ranges
        try:
            client_ip_obj = ipaddress.ip_address(client_ip)
            
            for ip_range in self.allowed_ip_ranges:
                if client_ip_obj in ipaddress.ip_network(ip_range):
                    return True
        except ValueError:
            pass
        
        return False

# Hierarchical authorization
class HierarchicalAuthorizationMixin:
    """Mixin for hierarchical authorization (manager/subordinate)"""
    
    def check_hierarchical_permissions(self, request, target_user):
        """Check if user has hierarchical permission over target user"""
        
        current_user = request.user
        
        # Superusers have access to everything
        if current_user.is_superuser:
            return True
        
        # Users can access their own data
        if current_user == target_user:
            return True
        
        # Check if current user is manager of target user
        if hasattr(current_user, 'subordinates'):
            if target_user in current_user.get_subordinates():
                return True
        
        # Check role hierarchy
        if self.check_role_hierarchy(current_user, target_user):
            return True
        
        return False
    
    def check_role_hierarchy(self, current_user, target_user):
        """Check role-based hierarchy"""
        
        # Define role hierarchy (higher number = higher authority)
        role_hierarchy = {
            'Employee': 1,
            'Team Lead': 2,
            'Manager': 3,
            'Director': 4,
            'VP': 5,
            'CEO': 6,
        }
        
        current_user_roles = current_user.groups.values_list('name', flat=True)
        target_user_roles = target_user.groups.values_list('name', flat=True)
        
        current_max_level = max(
            [role_hierarchy.get(role, 0) for role in current_user_roles],
            default=0
        )
        
        target_max_level = max(
            [role_hierarchy.get(role, 0) for role in target_user_roles],
            default=0
        )
        
        return current_max_level > target_max_level

class UserManagementView(HierarchicalAuthorizationMixin, DetailView):
    """View for managing user details with hierarchical permissions"""
    
    model = User
    template_name = 'user_detail.html'
    
    def dispatch(self, request, *args, **kwargs):
        """Check hierarchical permissions"""
        
        target_user = self.get_object()
        
        if not self.check_hierarchical_permissions(request, target_user):
            raise PermissionDenied(
                "You don't have permission to view this user's details."
            )
        
        return super().dispatch(request, *args, **kwargs)

Implementing comprehensive authorization in views and templates ensures that your Django application maintains proper access control at every level. By combining Django's built-in authorization tools with custom logic and template-level permission checks, you can create secure, user-friendly applications that properly restrict access based on user roles, permissions, and contextual factors.