Skip to content

Commit 4cd49d5

Browse files
committed
2 parents c573e7b + 1c0db6d commit 4cd49d5

File tree

10 files changed

+48
-16
lines changed

10 files changed

+48
-16
lines changed

docs/api-guide/pagination.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ This pagination style mirrors the syntax used when looking up multiple database
127127

128128
#### Setup
129129

130-
To enable the `PageNumberPagination` style globally, use the following configuration:
130+
To enable the `LimitOffsetPagination` style globally, use the following configuration:
131131

132132
REST_FRAMEWORK = {
133133
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'

docs/api-guide/testing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ When testing views directly using a request factory, it's often convenient to be
6565

6666
To forcibly authenticate a request, use the `force_authenticate()` method.
6767

68-
from rest_framework.tests import force_authenticate
68+
from rest_framework.test import force_authenticate
6969

7070
factory = APIRequestFactory()
7171
user = User.objects.get(username='olivia')

docs/topics/3.1-announcement.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,4 @@ This will either be made as a single 3.2 release, or split across two separate r
206206
[pagination]: ../api-guide/pagination.md
207207
[versioning]: ../api-guide/versioning.md
208208
[internationalization]: internationalization.md
209-
[customizing-field-mappings]: ../api-guide/serializers.md/#customizing-field-mappings
209+
[customizing-field-mappings]: ../api-guide/serializers.md#customizing-field-mappings

docs/topics/release-notes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ For older release notes, [please see the version 2.x documentation](old-release-
154154
[2.1.0-notes]: https://groups.google.com/d/topic/django-rest-framework/Vv2M0CMY9bg/discussion
155155
[ticket-582]: https://github.com/tomchristie/django-rest-framework/issues/582
156156
[rfc-6266]: http://tools.ietf.org/html/rfc6266#section-4.3
157-
[old-release-notes]: http://tomchristie.github.io/rest-framework-2-docs/topics/release-notes#24x-series
157+
[old-release-notes]: https://github.com/tomchristie/django-rest-framework/blob/version-2.4.x/docs/topics/release-notes.md
158158

159159
[3.0.1-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.0.1+Release%22
160160
[3.0.2-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.0.2+Release%22

docs/tutorial/2-requests-and-responses.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ See the [browsable api][browsable-api] topic for more information about the brow
200200

201201
In [tutorial part 3][tut-3], we'll start using class based views, and see how generic views reduce the amount of code we need to write.
202202

203-
[json-url]: http://example.com/api/items/4.json
203+
[json-url]: http://example.com/api/items/4/.json
204204
[devserver]: http://127.0.0.1:8000/snippets/
205205
[browsable-api]: ../topics/browsable-api.md
206206
[tut-1]: 1-serialization.md

rest_framework/pagination.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from django.template import Context, loader
1111
from django.utils import six
1212
from django.utils.six.moves.urllib import parse as urlparse
13-
from django.utils.translation import ugettext as _
13+
from django.utils.translation import ugettext_lazy as _
1414
from rest_framework.compat import OrderedDict
1515
from rest_framework.exceptions import NotFound
1616
from rest_framework.response import Response

rest_framework/routers.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,15 @@ def get_lookup_regex(self, viewset, lookup_prefix=''):
218218
219219
https://github.com/alanjds/drf-nested-routers
220220
"""
221-
base_regex = '(?P<{lookup_prefix}{lookup_field}>{lookup_value})'
221+
base_regex = '(?P<{lookup_prefix}{lookup_url_kwarg}>{lookup_value})'
222222
# Use `pk` as default field, unset set. Default regex should not
223223
# consume `.json` style suffixes and should break at '/' boundaries.
224224
lookup_field = getattr(viewset, 'lookup_field', 'pk')
225+
lookup_url_kwarg = getattr(viewset, 'lookup_url_kwarg', None) or lookup_field
225226
lookup_value = getattr(viewset, 'lookup_value_regex', '[^/.]+')
226227
return base_regex.format(
227228
lookup_prefix=lookup_prefix,
228-
lookup_field=lookup_field,
229+
lookup_url_kwarg=lookup_url_kwarg,
229230
lookup_value=lookup_value
230231
)
231232

rest_framework/templates/rest_framework/pagination/previous_and_next.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
{% if next_url %}
88
<li class="next"><a href="{{ next_url }}">Next &raquo;</a></li>
99
{% else %}
10-
<li class="next disabled"><a href="#">Next &raquo;</li>
10+
<li class="next disabled"><a href="#">Next &raquo;</a></li>
1111
{% endif %}
1212
</ul>

tests/conftest.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ def pytest_configure():
1818
MIDDLEWARE_CLASSES=(
1919
'django.middleware.common.CommonMiddleware',
2020
'django.contrib.sessions.middleware.SessionMiddleware',
21-
'django.middleware.csrf.CsrfViewMiddleware',
2221
'django.contrib.auth.middleware.AuthenticationMiddleware',
2322
'django.contrib.messages.middleware.MessageMiddleware',
2423
),
@@ -27,20 +26,14 @@ def pytest_configure():
2726
'django.contrib.contenttypes',
2827
'django.contrib.sessions',
2928
'django.contrib.sites',
30-
'django.contrib.messages',
3129
'django.contrib.staticfiles',
3230

3331
'rest_framework',
3432
'rest_framework.authtoken',
3533
'tests',
3634
),
3735
PASSWORD_HASHERS=(
38-
'django.contrib.auth.hashers.SHA1PasswordHasher',
39-
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
40-
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
41-
'django.contrib.auth.hashers.BCryptPasswordHasher',
4236
'django.contrib.auth.hashers.MD5PasswordHasher',
43-
'django.contrib.auth.hashers.CryptPasswordHasher',
4437
),
4538
)
4639

tests/test_routers.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ class NoteViewSet(viewsets.ModelViewSet):
3232
lookup_field = 'uuid'
3333

3434

35+
class KWargedNoteViewSet(viewsets.ModelViewSet):
36+
queryset = RouterTestModel.objects.all()
37+
serializer_class = NoteSerializer
38+
lookup_field = 'text__contains'
39+
lookup_url_kwarg = 'text'
40+
41+
3542
class MockViewSet(viewsets.ModelViewSet):
3643
queryset = None
3744
serializer_class = None
@@ -40,13 +47,17 @@ class MockViewSet(viewsets.ModelViewSet):
4047
notes_router = SimpleRouter()
4148
notes_router.register(r'notes', NoteViewSet)
4249

50+
kwarged_notes_router = SimpleRouter()
51+
kwarged_notes_router.register(r'notes', KWargedNoteViewSet)
52+
4353
namespaced_router = DefaultRouter()
4454
namespaced_router.register(r'example', MockViewSet, base_name='example')
4555

4656
urlpatterns = [
4757
url(r'^non-namespaced/', include(namespaced_router.urls)),
4858
url(r'^namespaced/', include(namespaced_router.urls, namespace='example')),
4959
url(r'^example/', include(notes_router.urls)),
60+
url(r'^example2/', include(kwarged_notes_router.urls)),
5061
]
5162

5263

@@ -177,6 +188,33 @@ def test_urls_limited_by_lookup_value_regex(self):
177188
self.assertEqual(expected[idx], self.urls[idx].regex.pattern)
178189

179190

191+
class TestLookupUrlKwargs(TestCase):
192+
"""
193+
Ensure the router honors lookup_url_kwarg.
194+
195+
Setup a deep lookup_field, but map it to a simple URL kwarg.
196+
"""
197+
urls = 'tests.test_routers'
198+
199+
def setUp(self):
200+
RouterTestModel.objects.create(uuid='123', text='foo bar')
201+
202+
def test_custom_lookup_url_kwarg_route(self):
203+
detail_route = kwarged_notes_router.urls[-1]
204+
detail_url_pattern = detail_route.regex.pattern
205+
self.assertIn('^notes/(?P<text>', detail_url_pattern)
206+
207+
def test_retrieve_lookup_url_kwarg_detail_view(self):
208+
response = self.client.get('/example2/notes/fo/')
209+
self.assertEqual(
210+
response.data,
211+
{
212+
"url": "http://testserver/example/notes/123/",
213+
"uuid": "123", "text": "foo bar"
214+
}
215+
)
216+
217+
180218
class TestTrailingSlashIncluded(TestCase):
181219
def setUp(self):
182220
class NoteViewSet(viewsets.ModelViewSet):

0 commit comments

Comments
 (0)