From 77be42ea6e9e28e44e115fd1979a8dae5b52e1f0 Mon Sep 17 00:00:00 2001 From: Manolis Stamatogiannakis Date: Thu, 27 Nov 2025 17:44:34 +0100 Subject: [PATCH] Updates for TokenAdmin. - Respect USERNAME_FIELD of the user model. - Default ordering by username. - Filter by creation date. --- rest_framework/authtoken/admin.py | 5 +++-- tests/test_authtoken.py | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/rest_framework/authtoken/admin.py b/rest_framework/authtoken/admin.py index eabb8fca8b..80d8d445fb 100644 --- a/rest_framework/authtoken/admin.py +++ b/rest_framework/authtoken/admin.py @@ -23,10 +23,11 @@ def url_for_result(self, result): class TokenAdmin(admin.ModelAdmin): list_display = ('key', 'user', 'created') + list_filter = ('created',) fields = ('user',) - search_fields = ('user__username',) + search_fields = ('user__%s' % User.USERNAME_FIELD,) search_help_text = _('Username') - ordering = ('-created',) + ordering = ('user__%s' % User.USERNAME_FIELD,) actions = None # Actions not compatible with mapped IDs. def get_changelist(self, request, **kwargs): diff --git a/tests/test_authtoken.py b/tests/test_authtoken.py index 3cfcbb3944..520bd29215 100644 --- a/tests/test_authtoken.py +++ b/tests/test_authtoken.py @@ -1,5 +1,6 @@ import importlib from io import StringIO +from unittest.mock import patch import pytest from django.contrib.admin import site @@ -11,7 +12,7 @@ from rest_framework.authtoken.admin import TokenAdmin from rest_framework.authtoken.management.commands.drf_create_token import \ Command as AuthTokenCommand -from rest_framework.authtoken.models import Token +from rest_framework.authtoken.models import Token, TokenProxy from rest_framework.authtoken.serializers import AuthTokenSerializer from rest_framework.exceptions import ValidationError @@ -36,6 +37,29 @@ def test_model_admin_displayed_fields(self): token_admin = TokenAdmin(self.token, self.site) assert token_admin.get_fields(mock_request) == ('user',) + @patch('django.contrib.admin.site.register') # avoid duplicate registrations + def test_model_admin__username_field(self, mock_register): + import rest_framework.authtoken.admin as authtoken_admin_m + + class EmailUser(User): + USERNAME_FIELD = 'email' + username = None + + for user_model in (User, EmailUser): + with ( + self.subTest(user_model=user_model), + patch('django.contrib.auth.get_user_model', return_value=user_model) as get_user_model + ): + importlib.reload(authtoken_admin_m) # reload after patching + assert get_user_model.call_count == 1 + + mock_request = object() + token_admin = authtoken_admin_m.TokenAdmin(TokenProxy, self.site) + assert token_admin.get_search_fields(mock_request) == (f'user__{user_model.USERNAME_FIELD}',) + assert token_admin.get_ordering(mock_request) == (f'user__{user_model.USERNAME_FIELD}',) + + importlib.reload(authtoken_admin_m) # restore after testing + def test_token_string_representation(self): assert str(self.token) == 'test token'