Skip to content

Commit 5777fb5

Browse files
committed
Fix authtoken.TokenProxy error when not installed in Django apps
1 parent 2e721cd commit 5777fb5

File tree

2 files changed

+57
-11
lines changed

2 files changed

+57
-11
lines changed

rest_framework/authtoken/models.py

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33

44
from django.conf import settings
5+
from django.core.exceptions import ImproperlyConfigured
56
from django.db import models
67
from django.utils.translation import gettext_lazy as _
78

@@ -40,14 +41,31 @@ def __str__(self):
4041
return self.key
4142

4243

43-
class TokenProxy(Token):
44-
"""
45-
Proxy mapping pk to user pk for use in admin.
46-
"""
47-
@property
48-
def pk(self):
49-
return self.user.pk
44+
if 'rest_framework.authtoken' in settings.INSTALLED_APPS:
45+
class TokenProxy(Token):
46+
"""
47+
Proxy mapping pk to user pk for use in admin.
48+
"""
49+
@property
50+
def pk(self):
51+
return self.user.pk
5052

51-
class Meta:
52-
proxy = True
53-
verbose_name = "token"
53+
class Meta:
54+
proxy = True
55+
verbose_name = "token"
56+
else:
57+
def improperly_configured(*args, **kwargs):
58+
raise ImproperlyConfigured(
59+
'"rest_framework.authtoken" must be in your '
60+
'settings.INSTALLED_APPS to use the Token or TokenProxy model.')
61+
62+
# throw improperly_configured when accessing TokenProxy.objects
63+
class Descriptor:
64+
def __get__(self, obj, type=None):
65+
improperly_configured()
66+
67+
class TokenProxy:
68+
def __init__(self, *args, **kwargs):
69+
improperly_configured()
70+
71+
objects = Descriptor()

tests/test_authtoken.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import importlib
12
from io import StringIO
23

34
import pytest
45
from django.contrib.admin import site
56
from django.contrib.auth.models import User
7+
from django.core.exceptions import ImproperlyConfigured
68
from django.core.management import CommandError, call_command
7-
from django.test import TestCase
9+
from django.db import models
10+
from django.test import TestCase, modify_settings
811

912
from rest_framework.authtoken.admin import TokenAdmin
1013
from rest_framework.authtoken.management.commands.drf_create_token import \
@@ -21,6 +24,31 @@ def setUp(self):
2124
self.user = User.objects.create_user(username='test_user')
2225
self.token = Token.objects.create(key='test token', user=self.user)
2326

27+
def test_authtoken_can_be_imported_when_not_installed(self):
28+
try:
29+
import rest_framework.authtoken.models
30+
authtoken_models = rest_framework.authtoken.models
31+
assert issubclass(authtoken_models.Token, models.Model)
32+
assert issubclass(authtoken_models.TokenProxy, models.Model)
33+
assert not authtoken_models.Token._meta.abstract
34+
assert authtoken_models.TokenProxy._meta.proxy
35+
36+
with modify_settings(INSTALLED_APPS={
37+
'remove': 'rest_framework.authtoken'}):
38+
importlib.reload(rest_framework.authtoken.models)
39+
authtoken_models = rest_framework.authtoken.models
40+
assert issubclass(authtoken_models.Token, models.Model)
41+
assert authtoken_models.Token._meta.abstract
42+
with pytest.raises(ImproperlyConfigured):
43+
authtoken_models.TokenProxy()
44+
with pytest.raises(ImproperlyConfigured):
45+
authtoken_models.TokenProxy.objects
46+
47+
finally:
48+
# Set the proxy and abstract properties back to the version,
49+
# where authtoken is among INSTALLED_APPS.
50+
importlib.reload(rest_framework.authtoken.models)
51+
2452
def test_model_admin_displayed_fields(self):
2553
mock_request = object()
2654
token_admin = TokenAdmin(self.token, self.site)

0 commit comments

Comments
 (0)