Skip to content

Commit 994e1ba

Browse files
Django 1.10 support. (#4158)
* Added TEMPLATES setting to tests * Remove deprecated view-string in URL conf * Replace 'urls = ...' in test classes with override_settings('ROOT_URLCONF=...') * Refactor UsingURLPatterns to use override_settings(ROOT_URLCONF=...) style * Get model managers and names in a version-compatible manner. * Apply override_settings to a TestCase, not a mixin class * Use '.callback' property instead of private attributes when inspecting urlpatterns * Pass 'user' to template explicitly * Correct sorting of import statements. * Remove unused TEMPLATE_LOADERS setting, in favor of TEMPLATES. * Remove code style issue * BaseFilter test requires a concrete model * Resolve tox.ini issues * Resolve isort differences between local and tox environments
1 parent fe2aede commit 994e1ba

24 files changed

+114
-123
lines changed

rest_framework/compat.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,23 @@ def distinct(queryset, base):
5858
return queryset.distinct()
5959

6060

61+
def get_names_and_managers(options):
62+
if django.VERSION >= (1, 10):
63+
# Django 1.10 onwards provides a `.managers` property on the Options.
64+
return [
65+
(manager.name, manager)
66+
for manager
67+
in options.managers
68+
]
69+
# For Django 1.8 and 1.9, use the three-tuple information provided
70+
# by .concrete_managers and .abstract_managers
71+
return [
72+
(manager_info[1], manager_info[2])
73+
for manager_info
74+
in (options.concrete_managers + options.abstract_managers)
75+
]
76+
77+
6178
# contrib.postgres only supported from 1.8 onwards.
6279
try:
6380
from django.contrib.postgres import fields as postgres_fields

rest_framework/renderers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ def get_context(self, data, accepted_media_type, renderer_context):
635635
'view': view,
636636
'request': request,
637637
'response': response,
638+
'user': request.user,
638639
'description': self.get_description(view, response.status_code),
639640
'name': self.get_name(view),
640641
'version': VERSION,

rest_framework/urlpatterns.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required):
2424
else:
2525
# Regular URL pattern
2626
regex = urlpattern.regex.pattern.rstrip('$').rstrip('/') + suffix_pattern
27-
view = urlpattern._callback or urlpattern._callback_str
27+
view = urlpattern.callback
2828
kwargs = urlpattern.default_args
2929
name = urlpattern.name
3030
# Add in both the existing and the new urlpattern

rest_framework/utils/representation.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010
from django.utils.encoding import force_text
1111
from django.utils.functional import Promise
1212

13-
from rest_framework.compat import unicode_repr
13+
from rest_framework.compat import get_names_and_managers, unicode_repr
1414

1515

1616
def manager_repr(value):
1717
model = value.model
1818
opts = model._meta
19-
for _, name, manager in opts.concrete_managers + opts.abstract_managers:
20-
if manager == value:
21-
return '%s.%s.all()' % (model._meta.object_name, name)
19+
for manager_name, manager_instance in get_names_and_managers(opts):
20+
if manager_instance == value:
21+
return '%s.%s.all()' % (model._meta.object_name, manager_name)
2222
return repr(value)
2323

2424

runtests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
FLAKE8_ARGS = ['rest_framework', 'tests', '--ignore=E501']
1616

17-
ISORT_ARGS = ['--recursive', '--check-only', 'rest_framework', 'tests']
17+
ISORT_ARGS = ['--recursive', '--check-only', '-p', 'tests', 'rest_framework', 'tests']
1818

1919
sys.path.append(os.path.dirname(__file__))
2020

tests/browsable_api/test_browsable_api.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
from __future__ import unicode_literals
22

33
from django.contrib.auth.models import User
4-
from django.test import TestCase
4+
from django.test import TestCase, override_settings
55

66
from rest_framework.test import APIClient
77

88

9+
@override_settings(ROOT_URLCONF='tests.browsable_api.auth_urls')
910
class DropdownWithAuthTests(TestCase):
1011
"""Tests correct dropdown behaviour with Auth views enabled."""
11-
12-
urls = 'tests.browsable_api.auth_urls'
13-
1412
def setUp(self):
1513
self.client = APIClient(enforce_csrf_checks=True)
1614
self.username = 'john'
@@ -40,11 +38,9 @@ def test_login_shown_when_logged_out(self):
4038
self.assertContains(response, '>Log in<')
4139

4240

41+
@override_settings(ROOT_URLCONF='tests.browsable_api.no_auth_urls')
4342
class NoDropdownWithoutAuthTests(TestCase):
4443
"""Tests correct dropdown behaviour with Auth views NOT enabled."""
45-
46-
urls = 'tests.browsable_api.no_auth_urls'
47-
4844
def setUp(self):
4945
self.client = APIClient(enforce_csrf_checks=True)
5046
self.username = 'john'

tests/browsable_api/views.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@
66

77

88
class MockView(APIView):
9-
109
authentication_classes = (authentication.SessionAuthentication,)
11-
renderer_classes = (renderers.BrowsableAPIRenderer,)
10+
renderer_classes = (renderers.BrowsableAPIRenderer, renderers.JSONRenderer)
1211

1312
def get(self, request):
1413
return Response({'a': 1, 'b': 2, 'c': 3})

tests/conftest.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,24 @@ def pytest_configure():
33

44
settings.configure(
55
DEBUG_PROPAGATE_EXCEPTIONS=True,
6-
DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3',
7-
'NAME': ':memory:'}},
6+
DATABASES={
7+
'default': {
8+
'ENGINE': 'django.db.backends.sqlite3',
9+
'NAME': ':memory:'
10+
}
11+
},
812
SITE_ID=1,
913
SECRET_KEY='not very secret in tests',
1014
USE_I18N=True,
1115
USE_L10N=True,
1216
STATIC_URL='/static/',
1317
ROOT_URLCONF='tests.urls',
14-
TEMPLATE_LOADERS=(
15-
'django.template.loaders.filesystem.Loader',
16-
'django.template.loaders.app_directories.Loader',
17-
),
18+
TEMPLATES=[
19+
{
20+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
21+
'APP_DIRS': True,
22+
},
23+
],
1824
MIDDLEWARE_CLASSES=(
1925
'django.middleware.common.CommonMiddleware',
2026
'django.contrib.sessions.middleware.SessionMiddleware',
@@ -27,7 +33,6 @@ def pytest_configure():
2733
'django.contrib.sessions',
2834
'django.contrib.sites',
2935
'django.contrib.staticfiles',
30-
3136
'rest_framework',
3237
'rest_framework.authtoken',
3338
'tests',

tests/models.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ class BasicModel(RESTFrameworkModel):
2727
class BaseFilterableItem(RESTFrameworkModel):
2828
text = models.CharField(max_length=100)
2929

30-
class Meta:
31-
abstract = True
32-
3330

3431
class FilterableItem(BaseFilterableItem):
3532
decimal = models.DecimalField(max_digits=4, decimal_places=2)

tests/test_authentication.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from django.contrib.auth.models import User
99
from django.db import models
1010
from django.http import HttpResponse
11-
from django.test import TestCase
11+
from django.test import TestCase, override_settings
1212
from django.utils import six
1313

1414
from rest_framework import (
@@ -19,6 +19,7 @@
1919
TokenAuthentication
2020
)
2121
from rest_framework.authtoken.models import Token
22+
from rest_framework.authtoken.views import obtain_auth_token
2223
from rest_framework.response import Response
2324
from rest_framework.test import APIClient, APIRequestFactory
2425
from rest_framework.views import APIView
@@ -75,15 +76,14 @@ def put(self, request):
7576
authentication_classes=[CustomKeywordTokenAuthentication]
7677
)
7778
),
78-
url(r'^auth-token/$', 'rest_framework.authtoken.views.obtain_auth_token'),
79+
url(r'^auth-token/$', obtain_auth_token),
7980
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
8081
]
8182

8283

84+
@override_settings(ROOT_URLCONF='tests.test_authentication')
8385
class BasicAuthTests(TestCase):
8486
"""Basic authentication"""
85-
urls = 'tests.test_authentication'
86-
8787
def setUp(self):
8888
self.csrf_client = APIClient(enforce_csrf_checks=True)
8989
self.username = 'john'
@@ -151,10 +151,9 @@ def test_post_json_failing_basic_auth(self):
151151
self.assertEqual(response['WWW-Authenticate'], 'Basic realm="api"')
152152

153153

154+
@override_settings(ROOT_URLCONF='tests.test_authentication')
154155
class SessionAuthTests(TestCase):
155156
"""User session authentication"""
156-
urls = 'tests.test_authentication'
157-
158157
def setUp(self):
159158
self.csrf_client = APIClient(enforce_csrf_checks=True)
160159
self.non_csrf_client = APIClient(enforce_csrf_checks=False)
@@ -223,7 +222,6 @@ def test_post_form_session_auth_failing(self):
223222

224223
class BaseTokenAuthTests(object):
225224
"""Token authentication"""
226-
urls = 'tests.test_authentication'
227225
model = None
228226
path = None
229227
header_prefix = 'Token '
@@ -311,6 +309,7 @@ def test_post_json_failing_token_auth(self):
311309
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
312310

313311

312+
@override_settings(ROOT_URLCONF='tests.test_authentication')
314313
class TokenAuthTests(BaseTokenAuthTests, TestCase):
315314
model = Token
316315
path = '/token/'
@@ -367,11 +366,13 @@ def test_token_login_form(self):
367366
self.assertEqual(response.data['token'], self.key)
368367

369368

369+
@override_settings(ROOT_URLCONF='tests.test_authentication')
370370
class CustomTokenAuthTests(BaseTokenAuthTests, TestCase):
371371
model = CustomToken
372372
path = '/customtoken/'
373373

374374

375+
@override_settings(ROOT_URLCONF='tests.test_authentication')
375376
class CustomKeywordTokenAuthTests(BaseTokenAuthTests, TestCase):
376377
model = Token
377378
path = '/customkeywordtoken/'

0 commit comments

Comments
 (0)