Authentication and Authorization

Users and Groups

Django's User and Group models form the foundation of the authentication and authorization system. Understanding how to work with users, organize them into groups, and manage their relationships is crucial for implementing effective access control in your Django applications.

Users and Groups

Django's User and Group models form the foundation of the authentication and authorization system. Understanding how to work with users, organize them into groups, and manage their relationships is crucial for implementing effective access control in your Django applications.

User Model Deep Dive

Built-in User Model

# Django's built-in User model
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model

# Always use get_user_model() for flexibility
User = get_user_model()

class UserModelExploration:
    """Comprehensive exploration of the User model"""
    
    @staticmethod
    def user_model_fields():
        """Explore User model fields and their purposes"""
        
        # Core identification fields
        user_fields = {
            'username': 'Unique identifier for login (max 150 chars)',
            'email': 'Email address (not unique by default)',
            'first_name': 'First name (max 150 chars)',
            'last_name': 'Last name (max 150 chars)',
            'password': 'Hashed password',
        }
        
        # Permission and status fields
        permission_fields = {
            'is_active': 'User account is active',
            'is_staff': 'User can access admin site',
            'is_superuser': 'User has all permissions',
        }
        
        # Timestamp fields
        timestamp_fields = {
            'date_joined': 'When user account was created',
            'last_login': 'Last successful login timestamp',
        }
        
        return {
            'user_fields': user_fields,
            'permission_fields': permission_fields,
            'timestamp_fields': timestamp_fields
        }
    
    @staticmethod
    def create_users_examples():
        """Examples of creating different types of users"""
        
        # Create regular user
        regular_user = User.objects.create_user(
            username='john_doe',
            email='john@example.com',
            password='secure_password123',
            first_name='John',
            last_name='Doe'
        )
        
        # Create staff user
        staff_user = User.objects.create_user(
            username='jane_staff',
            email='jane@company.com',
            password='staff_password123',
            first_name='Jane',
            last_name='Staff',
            is_staff=True
        )
        
        # Create superuser
        superuser = User.objects.create_superuser(
            username='admin',
            email='admin@company.com',
            password='admin_password123',
            first_name='Admin',
            last_name='User'
        )
        
        return {
            'regular_user': regular_user,
            'staff_user': staff_user,
            'superuser': superuser
        }
    
    @staticmethod
    def user_methods_demonstration():
        """Demonstrate important User model methods"""
        
        user = User.objects.create_user(
            username='demo_user',
            email='demo@example.com',
            password='demo_password123',
            first_name='Demo',
            last_name='User'
        )
        
        # Authentication methods
        auth_methods = {
            'check_password': user.check_password('demo_password123'),  # True
            'has_usable_password': user.has_usable_password(),  # True
            'set_unusable_password': 'user.set_unusable_password()',  # Disables password login
        }
        
        # Name methods
        name_methods = {
            'get_full_name': user.get_full_name(),  # "Demo User"
            'get_short_name': user.get_short_name(),  # "Demo"
            'get_username': user.get_username(),  # "demo_user"
        }
        
        # Status properties
        status_properties = {
            'is_authenticated': user.is_authenticated,  # True (for real users)
            'is_anonymous': user.is_anonymous,  # False (for real users)
            'is_active': user.is_active,  # True by default
            'is_staff': user.is_staff,  # False by default
            'is_superuser': user.is_superuser,  # False by default
        }
        
        return {
            'auth_methods': auth_methods,
            'name_methods': name_methods,
            'status_properties': status_properties
        }

# Advanced user management
class AdvancedUserManagement:
    """Advanced user management techniques"""
    
    @staticmethod
    def bulk_user_operations():
        """Perform bulk operations on users"""
        
        # Bulk create users
        users_data = [
            {'username': f'user_{i}', 'email': f'user{i}@example.com', 'password': 'temp_password'}
            for i in range(1, 101)
        ]
        
        users_to_create = []
        for user_data in users_data:
            user = User(
                username=user_data['username'],
                email=user_data['email']
            )
            user.set_password(user_data['password'])
            users_to_create.append(user)
        
        # Bulk create (more efficient than individual creates)
        created_users = User.objects.bulk_create(users_to_create)
        
        # Bulk update users
        User.objects.filter(username__startswith='user_').update(
            is_active=True,
            first_name='Bulk',
            last_name='User'
        )
        
        # Bulk delete inactive users
        deleted_count = User.objects.filter(
            is_active=False,
            last_login__isnull=True,
            date_joined__lt=timezone.now() - timedelta(days=30)
        ).delete()
        
        return {
            'created_count': len(created_users),
            'deleted_count': deleted_count[0] if deleted_count else 0
        }
    
    @staticmethod
    def user_filtering_and_queries():
        """Advanced user filtering and queries"""
        
        from django.db.models import Q, Count, Max, Min
        from datetime import timedelta
        
        # Active users who logged in recently
        recent_active_users = User.objects.filter(
            is_active=True,
            last_login__gte=timezone.now() - timedelta(days=7)
        )
        
        # Users with specific permissions
        users_with_add_permission = User.objects.filter(
            Q(user_permissions__codename='add_post') |
            Q(groups__permissions__codename='add_post')
        ).distinct()
        
        # Staff users without superuser privileges
        staff_non_super = User.objects.filter(
            is_staff=True,
            is_superuser=False
        )
        
        # Users by registration period
        new_users = User.objects.filter(
            date_joined__gte=timezone.now() - timedelta(days=30)
        )
        
        # Users with email domains
        company_users = User.objects.filter(
            email__endswith='@company.com'
        )
        
        # Complex queries with annotations
        user_stats = User.objects.annotate(
            group_count=Count('groups'),
            permission_count=Count('user_permissions')
        ).filter(
            group_count__gt=0
        )
        
        return {
            'recent_active': recent_active_users.count(),
            'with_add_permission': users_with_add_permission.count(),
            'staff_non_super': staff_non_super.count(),
            'new_users': new_users.count(),
            'company_users': company_users.count(),
            'users_with_groups': user_stats.count()
        }
    
    @staticmethod
    def user_profile_management():
        """Manage user profiles and extended information"""
        
        # Example user profile model
        class UserProfile(models.Model):
            user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
            bio = models.TextField(max_length=500, blank=True)
            location = models.CharField(max_length=30, blank=True)
            birth_date = models.DateField(null=True, blank=True)
            avatar = models.ImageField(upload_to='avatars/', blank=True)
            phone_number = models.CharField(max_length=15, blank=True)
            website = models.URLField(blank=True)
            
            # Preferences
            email_notifications = models.BooleanField(default=True)
            theme_preference = models.CharField(
                max_length=10,
                choices=[('light', 'Light'), ('dark', 'Dark')],
                default='light'
            )
            
            created_at = models.DateTimeField(auto_now_add=True)
            updated_at = models.DateTimeField(auto_now=True)
            
            def __str__(self):
                return f"{self.user.username}'s Profile"
            
            def get_age(self):
                if self.birth_date:
                    today = timezone.now().date()
                    return today.year - self.birth_date.year - (
                        (today.month, today.day) < (self.birth_date.month, self.birth_date.day)
                    )
                return None
        
        # Signal to create profile automatically
        from django.db.models.signals import post_save
        from django.dispatch import receiver
        
        @receiver(post_save, sender=User)
        def create_user_profile(sender, instance, created, **kwargs):
            if created:
                UserProfile.objects.create(user=instance)
        
        @receiver(post_save, sender=User)
        def save_user_profile(sender, instance, **kwargs):
            if hasattr(instance, 'profile'):
                instance.profile.save()
        
        return UserProfile

Group Management

Understanding Groups

# Django's Group model for organizing users
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType

class GroupManagement:
    """Comprehensive group management"""
    
    @staticmethod
    def create_groups_with_permissions():
        """Create groups and assign permissions"""
        
        # Create groups for different user roles
        groups_config = {
            'Editors': [
                'add_post', 'change_post', 'delete_post', 'view_post',
                'add_category', 'change_category', 'view_category'
            ],
            'Moderators': [
                'change_post', 'delete_post', 'view_post',
                'add_comment', 'change_comment', 'delete_comment', 'view_comment'
            ],
            'Authors': [
                'add_post', 'change_post', 'view_post'
            ],
            'Subscribers': [
                'view_post', 'add_comment', 'change_comment'
            ]
        }
        
        created_groups = {}
        
        for group_name, permission_codenames in groups_config.items():
            # Create or get group
            group, created = Group.objects.get_or_create(name=group_name)
            
            # Get permissions
            permissions = Permission.objects.filter(
                codename__in=permission_codenames
            )
            
            # Assign permissions to group
            group.permissions.set(permissions)
            
            created_groups[group_name] = {
                'group': group,
                'created': created,
                'permissions_count': permissions.count()
            }
        
        return created_groups
    
    @staticmethod
    def manage_group_membership():
        """Manage users in groups"""
        
        # Get groups
        editors_group = Group.objects.get(name='Editors')
        authors_group = Group.objects.get(name='Authors')
        
        # Add users to groups
        editor_users = User.objects.filter(is_staff=True, is_superuser=False)
        for user in editor_users:
            user.groups.add(editors_group)
        
        # Add specific users to authors group
        author_usernames = ['john_doe', 'jane_author', 'bob_writer']
        author_users = User.objects.filter(username__in=author_usernames)
        authors_group.user_set.add(*author_users)
        
        # Remove users from group
        inactive_users = User.objects.filter(is_active=False)
        for group in Group.objects.all():
            group.user_set.remove(*inactive_users)
        
        return {
            'editors_count': editors_group.user_set.count(),
            'authors_count': authors_group.user_set.count()
        }
    
    @staticmethod
    def group_hierarchy_simulation():
        """Simulate group hierarchy with custom logic"""
        
        # Define group hierarchy
        group_hierarchy = {
            'Administrators': {
                'level': 1,
                'inherits_from': [],
                'permissions': ['*']  # All permissions
            },
            'Managers': {
                'level': 2,
                'inherits_from': ['Editors', 'Moderators'],
                'permissions': ['manage_users', 'view_reports']
            },
            'Editors': {
                'level': 3,
                'inherits_from': ['Authors'],
                'permissions': ['edit_any_post', 'publish_post']
            },
            'Authors': {
                'level': 4,
                'inherits_from': ['Subscribers'],
                'permissions': ['create_post', 'edit_own_post']
            },
            'Subscribers': {
                'level': 5,
                'inherits_from': [],
                'permissions': ['view_content', 'comment']
            }
        }
        
        def get_effective_permissions(user):
            """Get all effective permissions for user including inherited"""
            
            effective_permissions = set()
            user_groups = user.groups.all()
            
            for group in user_groups:
                # Add direct group permissions
                group_perms = group.permissions.all()
                effective_permissions.update(perm.codename for perm in group_perms)
                
                # Add inherited permissions
                if group.name in group_hierarchy:
                    inherits_from = group_hierarchy[group.name]['inherits_from']
                    
                    for parent_group_name in inherits_from:
                        try:
                            parent_group = Group.objects.get(name=parent_group_name)
                            parent_perms = parent_group.permissions.all()
                            effective_permissions.update(perm.codename for perm in parent_perms)
                        except Group.DoesNotExist:
                            continue
            
            return effective_permissions
        
        return get_effective_permissions
    
    @staticmethod
    def dynamic_group_assignment():
        """Dynamically assign users to groups based on criteria"""
        
        def auto_assign_groups():
            """Automatically assign users to appropriate groups"""
            
            # Get groups
            try:
                editors_group = Group.objects.get(name='Editors')
                authors_group = Group.objects.get(name='Authors')
                subscribers_group = Group.objects.get(name='Subscribers')
            except Group.DoesNotExist:
                return "Groups not found"
            
            # Auto-assign based on user attributes
            for user in User.objects.filter(is_active=True):
                # Staff users become editors
                if user.is_staff and not user.is_superuser:
                    user.groups.add(editors_group)
                
                # Users with posts become authors
                elif hasattr(user, 'posts') and user.posts.exists():
                    user.groups.add(authors_group)
                
                # All other active users are subscribers
                else:
                    user.groups.add(subscribers_group)
            
            return "Auto-assignment completed"
        
        def assign_based_on_activity():
            """Assign groups based on user activity"""
            
            from django.db.models import Count
            
            # Users with many posts become editors
            prolific_users = User.objects.annotate(
                post_count=Count('posts')
            ).filter(post_count__gte=10)
            
            editors_group = Group.objects.get(name='Editors')
            for user in prolific_users:
                user.groups.add(editors_group)
            
            # Users with recent activity remain active
            recent_users = User.objects.filter(
                last_login__gte=timezone.now() - timedelta(days=30)
            )
            
            # Remove inactive users from all groups
            inactive_users = User.objects.exclude(
                id__in=recent_users.values_list('id', flat=True)
            )
            
            for user in inactive_users:
                user.groups.clear()
        
        return auto_assign_groups, assign_based_on_activity

# Advanced group queries and operations
class AdvancedGroupOperations:
    """Advanced operations with groups"""
    
    @staticmethod
    def group_analytics():
        """Analyze group membership and permissions"""
        
        from django.db.models import Count, Q
        
        # Group membership statistics
        group_stats = Group.objects.annotate(
            user_count=Count('user'),
            permission_count=Count('permissions')
        ).order_by('-user_count')
        
        # Users with multiple groups
        multi_group_users = User.objects.annotate(
            group_count=Count('groups')
        ).filter(group_count__gt=1)
        
        # Groups with specific permissions
        groups_with_add_perms = Group.objects.filter(
            permissions__codename__startswith='add_'
        ).distinct()
        
        # Orphaned permissions (not assigned to any group)
        orphaned_permissions = Permission.objects.filter(
            group__isnull=True,
            user__isnull=True
        )
        
        analytics = {
            'total_groups': Group.objects.count(),
            'groups_with_users': group_stats.filter(user_count__gt=0).count(),
            'multi_group_users': multi_group_users.count(),
            'groups_with_add_perms': groups_with_add_perms.count(),
            'orphaned_permissions': orphaned_permissions.count(),
            'group_details': [
                {
                    'name': group.name,
                    'user_count': group.user_count,
                    'permission_count': group.permission_count
                }
                for group in group_stats
            ]
        }
        
        return analytics
    
    @staticmethod
    def group_permission_matrix():
        """Create a permission matrix for all groups"""
        
        groups = Group.objects.prefetch_related('permissions').all()
        all_permissions = Permission.objects.all().order_by('content_type__app_label', 'codename')
        
        matrix = {}
        
        for group in groups:
            group_permissions = set(group.permissions.values_list('id', flat=True))
            matrix[group.name] = {}
            
            for permission in all_permissions:
                matrix[group.name][f"{permission.content_type.app_label}.{permission.codename}"] = (
                    permission.id in group_permissions
                )
        
        return matrix
    
    @staticmethod
    def cleanup_groups():
        """Clean up unused groups and optimize group structure"""
        
        cleanup_results = {
            'empty_groups_removed': 0,
            'duplicate_permissions_cleaned': 0,
            'inactive_users_removed': 0
        }
        
        # Remove empty groups (no users and no permissions)
        empty_groups = Group.objects.annotate(
            user_count=Count('user'),
            permission_count=Count('permissions')
        ).filter(user_count=0, permission_count=0)
        
        cleanup_results['empty_groups_removed'] = empty_groups.count()
        empty_groups.delete()
        
        # Remove inactive users from all groups
        inactive_users = User.objects.filter(is_active=False)
        for user in inactive_users:
            removed_count = user.groups.count()
            user.groups.clear()
            cleanup_results['inactive_users_removed'] += removed_count
        
        # Clean up duplicate permissions in groups
        for group in Group.objects.all():
            permissions = list(group.permissions.all())
            unique_permissions = list(set(permissions))
            
            if len(permissions) != len(unique_permissions):
                group.permissions.set(unique_permissions)
                cleanup_results['duplicate_permissions_cleaned'] += (
                    len(permissions) - len(unique_permissions)
                )
        
        return cleanup_results

# Group-based access control
class GroupBasedAccessControl:
    """Implement group-based access control patterns"""
    
    @staticmethod
    def group_required_decorator():
        """Decorator to require specific group membership"""
        
        from functools import wraps
        from django.core.exceptions import PermissionDenied
        
        def group_required(*group_names):
            def decorator(view_func):
                @wraps(view_func)
                def wrapper(request, *args, **kwargs):
                    if not request.user.is_authenticated:
                        from django.contrib.auth.views import redirect_to_login
                        return redirect_to_login(request.get_full_path())
                    
                    user_groups = request.user.groups.values_list('name', flat=True)
                    
                    if not any(group in user_groups for group in group_names):
                        raise PermissionDenied(
                            f"Access denied. Required groups: {', '.join(group_names)}"
                        )
                    
                    return view_func(request, *args, **kwargs)
                
                return wrapper
            return decorator
        
        return group_required
    
    @staticmethod
    def group_based_queryset_filtering():
        """Filter querysets based on user's group membership"""
        
        def get_filtered_queryset(user, model_class):
            """Get queryset filtered by user's group permissions"""
            
            if user.is_superuser:
                return model_class.objects.all()
            
            user_groups = user.groups.values_list('name', flat=True)
            
            # Define group-based filtering rules
            if 'Administrators' in user_groups:
                return model_class.objects.all()
            
            elif 'Editors' in user_groups:
                # Editors can see all published content and their own drafts
                return model_class.objects.filter(
                    Q(status='published') | Q(author=user)
                )
            
            elif 'Authors' in user_groups:
                # Authors can only see their own content
                return model_class.objects.filter(author=user)
            
            else:
                # Default: only published content
                return model_class.objects.filter(status='published')
        
        return get_filtered_queryset
    
    @staticmethod
    def hierarchical_group_permissions():
        """Implement hierarchical group permissions"""
        
        def user_can_access_group_level(user, required_level):
            """Check if user has access to a specific group level"""
            
            group_levels = {
                'Administrators': 1,
                'Managers': 2,
                'Editors': 3,
                'Authors': 4,
                'Subscribers': 5
            }
            
            user_groups = user.groups.values_list('name', flat=True)
            user_level = min(
                [group_levels.get(group, 999) for group in user_groups],
                default=999
            )
            
            return user_level <= required_level
        
        def get_accessible_content(user):
            """Get content accessible to user based on group hierarchy"""
            
            user_groups = user.groups.values_list('name', flat=True)
            
            # Define content access levels
            if any(group in ['Administrators', 'Managers'] for group in user_groups):
                access_level = 'all'
            elif 'Editors' in user_groups:
                access_level = 'editorial'
            elif 'Authors' in user_groups:
                access_level = 'authoring'
            else:
                access_level = 'public'
            
            return access_level
        
        return user_can_access_group_level, get_accessible_content

Understanding Users and Groups in Django enables you to build sophisticated access control systems. By properly organizing users into groups and managing their permissions, you can create scalable authorization schemes that grow with your application's complexity.