CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-djangorestframework-jwt

JSON Web Token based authentication for Django REST framework

Pending
Overview
Eval results
Files

compatibility.mddocs/

Compatibility Utilities

Helper functions and classes for cross-version compatibility and Django integration, including user model handling and field utilities. These utilities ensure the JWT package works across different Django and Django REST Framework versions.

Capabilities

User Model Utilities

Functions for handling Django user model interactions across different configurations.

def get_username_field():
    """
    Returns the username field name from the configured User model.
    
    Returns:
        str: Username field name (e.g., 'username', 'email', 'phone')
        
    Notes:
        - Uses User.USERNAME_FIELD if available
        - Falls back to 'username' if User model is not accessible
        - Handles cases where User model is not properly configured
        
    Examples:
        - Default Django User: returns 'username'
        - Custom User with email auth: returns 'email'
        - Custom User with phone auth: returns 'phone'
    """

def get_username(user):
    """
    Extracts username value from a user instance.
    
    Args:
        user: Django user model instance
        
    Returns:
        str: Username value from the user instance
        
    Notes:
        - Uses user.get_username() method if available (Django 1.5+)
        - Falls back to user.username attribute for older versions
        - Handles different User model implementations
        
    Compatibility:
        - Django 1.4: Uses user.username attribute
        - Django 1.5+: Uses user.get_username() method
    """

Serializer Compatibility

Compatibility layer for Django REST Framework serializer changes across versions.

class Serializer(serializers.Serializer):
    @property
    def object(self):
        """
        Backward compatibility property for accessing validated data.
        
        Returns:
            dict: Validated data from the serializer
            
        Notes:
            - In DRF 3.0+: Returns self.validated_data
            - Provides compatibility for code expecting .object attribute
            - Deprecated in newer DRF versions but maintained for compatibility
        """

Form Field Utilities

Custom field classes that ensure consistent behavior across framework versions.

class PasswordField(serializers.CharField):
    def __init__(self, *args, **kwargs):
        """
        Password input field with consistent styling across DRF versions.
        
        Args:
            *args: Positional arguments for CharField
            **kwargs: Keyword arguments for CharField
            
        Features:
            - Automatically sets input_type to 'password'
            - Preserves existing style configuration if provided
            - Ensures password fields are rendered with proper input type
            
        Usage:
            password = PasswordField(write_only=True, required=True)
        """

Usage Examples

Custom User Model Integration

from rest_framework_jwt.compat import get_username_field, get_username
from django.contrib.auth import get_user_model

User = get_user_model()

# Handle different username field configurations
username_field = get_username_field()
print(f"Authentication uses field: {username_field}")

# Example with email-based authentication
class EmailUser(AbstractUser):
    email = models.EmailField(unique=True)
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

# get_username_field() returns 'email'
# get_username(user_instance) returns user.email value

Serializer Backward Compatibility

from rest_framework_jwt.compat import Serializer
from rest_framework import serializers

class CustomAuthSerializer(Serializer):  # Using compat Serializer
    username = serializers.CharField()
    password = serializers.CharField()
    
    def validate(self, attrs):
        # Validation logic here
        return attrs

# Usage that works across DRF versions
serializer = CustomAuthSerializer(data=request.data)
if serializer.is_valid():
    # Both work due to compatibility layer:
    data = serializer.object          # Backward compatibility
    data = serializer.validated_data  # Modern approach

Password Field Usage

from rest_framework_jwt.compat import PasswordField
from rest_framework import serializers

class LoginSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = PasswordField(write_only=True)  # Ensures password input type
    
    # Rendered as <input type="password"> in forms
    # Ensures consistent behavior across DRF versions

Cross-Version User Handling

from rest_framework_jwt.compat import get_username, get_username_field
from django.contrib.auth import get_user_model

def create_jwt_payload(user):
    """Create JWT payload compatible with any User model configuration."""
    
    # Get username regardless of field name or Django version
    username = get_username(user)
    username_field = get_username_field()
    
    payload = {
        'user_id': user.pk,
        'username': username,
        username_field: username,  # Include both for flexibility
    }
    
    return payload

def authenticate_user(credentials):
    """Authenticate user with dynamic username field."""
    User = get_user_model()
    username_field = get_username_field()
    
    # Build authentication kwargs dynamically
    auth_kwargs = {
        username_field: credentials.get(username_field),
        'password': credentials.get('password'),
    }
    
    return authenticate(**auth_kwargs)

Form Integration

from django import forms
from rest_framework_jwt.compat import PasswordField

class JWTAuthForm(forms.Form):
    """Django form using JWT-compatible password field."""
    
    username = forms.CharField(max_length=150)
    password = forms.CharField(widget=forms.PasswordInput)
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        # Dynamically set username field label
        from rest_framework_jwt.compat import get_username_field
        username_field = get_username_field()
        
        if username_field == 'email':
            self.fields['username'].label = 'Email Address'
            self.fields['username'].widget.attrs['type'] = 'email'
        elif username_field == 'phone':
            self.fields['username'].label = 'Phone Number'
            self.fields['username'].widget.attrs['type'] = 'tel'

Django Version Compatibility

User Model Evolution

# Django 1.4 and earlier
class User(models.Model):
    username = models.CharField(max_length=30, unique=True)
    
    # get_username() method not available
    # Must access username attribute directly

# Django 1.5+
class User(AbstractBaseUser):
    USERNAME_FIELD = 'username'  # Configurable username field
    
    def get_username(self):
        return getattr(self, self.USERNAME_FIELD)

# Custom implementations
class CustomUser(AbstractUser):
    USERNAME_FIELD = 'email'  # Use email instead of username
    
    def get_username(self):
        return self.email

DRF Serializer Changes

# DRF 2.x
class MySerializer(serializers.Serializer):
    def restore_object(self, attrs, instance=None):
        # Old validation method
        pass
    
    # Access via .object attribute
    serializer.object

# DRF 3.0+
class MySerializer(serializers.Serializer):
    def validate(self, attrs):
        # New validation method
        return attrs
    
    # Access via .validated_data attribute
    serializer.validated_data

# Compatibility layer bridges these differences

Error Handling

Graceful Fallbacks

def get_username_field():
    try:
        # Try to get USERNAME_FIELD from User model
        username_field = get_user_model().USERNAME_FIELD
    except:
        # Fallback to default if User model is not accessible
        username_field = 'username'
    
    return username_field

def get_username(user):
    try:
        # Try modern get_username() method
        username = user.get_username()
    except AttributeError:
        # Fallback to direct attribute access
        username = user.username
    
    return username

Common Compatibility Issues

# Issue: Different User model configurations
# Solution: Use get_username_field() and get_username()

# Issue: DRF serializer API changes  
# Solution: Use compat.Serializer with .object property

# Issue: Password field rendering inconsistencies
# Solution: Use compat.PasswordField with proper input type

# Issue: Import errors across Django versions
# Solution: Try/except blocks with fallback implementations

Testing Compatibility

Multi-Version Testing

# Test with different User model configurations
@override_settings(AUTH_USER_MODEL='myapp.EmailUser')
def test_email_based_auth(self):
    # Test JWT with email-based user model
    pass

@override_settings(AUTH_USER_MODEL='myapp.PhoneUser')  
def test_phone_based_auth(self):
    # Test JWT with phone-based user model
    pass

# Test serializer compatibility
def test_serializer_object_access(self):
    serializer = CustomSerializer(data={'test': 'data'})
    serializer.is_valid()
    
    # Both should work
    data1 = serializer.object
    data2 = serializer.validated_data
    assert data1 == data2

Integration Patterns

Flexible Authentication

from rest_framework_jwt.compat import get_username_field

class FlexibleJWTSerializer(serializers.Serializer):
    """Serializer that adapts to any User model configuration."""
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        # Add username field based on User model
        username_field = get_username_field()
        self.fields[username_field] = serializers.CharField()
        self.fields['password'] = PasswordField(write_only=True)
    
    def validate(self, attrs):
        username_field = get_username_field()
        username = attrs.get(username_field)
        password = attrs.get('password')
        
        if username and password:
            user = authenticate(**{
                username_field: username,
                'password': password
            })
            
            if user and user.is_active:
                return {'user': user}
        
        raise serializers.ValidationError('Invalid credentials')

The compatibility utilities ensure that JWT authentication works reliably across different Django versions, user model configurations, and DRF versions while maintaining clean, maintainable code.

Install with Tessl CLI

npx tessl i tessl/pypi-djangorestframework-jwt

docs

authentication.md

compatibility.md

configuration.md

index.md

jwt-utilities.md

serializers.md

views-endpoints.md

tile.json