Skip to content

revert JSONAPI prefix to JsonApi for paginators. #469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Sep 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7b29f36
initial integration of JSONAPIDjangoFilter
n2ygk Aug 23, 2018
dc5ca38
documentation, isort, flake8
n2ygk Aug 24, 2018
6b0dc8c
Forgot to add django_filters to installed_apps
n2ygk Aug 24, 2018
d4fbf24
backwards compatibility for py27 + django-filter
n2ygk Aug 24, 2018
d86d217
handle optional django-filter package
n2ygk Aug 24, 2018
83c4cc0
fix travis to match new TOXENVs due to django-filter
n2ygk Aug 24, 2018
f5792c1
fixed a typo
n2ygk Aug 24, 2018
cbc9d55
add a warning if django-filter is missing and JSONAPIDjangoFilter is …
n2ygk Aug 25, 2018
4f2b75b
improve filter_regex
n2ygk Aug 28, 2018
6a8d7ae
easy changes recommended by @sliverc review
n2ygk Aug 29, 2018
db9e1f9
resolve @sliverc review method of using optional django-filter.
n2ygk Aug 29, 2018
51b9946
rename JSONAPIDjangoFilter to DjangoFilterBackend.
n2ygk Aug 30, 2018
cfe89ea
Revert "deprecated JsonApi paginators class prefix to JSONAPI prefix …
n2ygk Aug 30, 2018
00dcf52
revert JSONAPI prefix from paginators
n2ygk Aug 30, 2018
fb17d78
override JSON_API_STANDARD_PAGINATION=False for test suite for now
n2ygk Aug 30, 2018
ee236ea
Merge branch 'master' into remove-JSONAPI-paginators
n2ygk Sep 6, 2018
6145d33
Revert "revert JSONAPI prefix from paginators"
n2ygk Sep 6, 2018
b90d983
Reverts JSONAPI prefix to JsonApi prefix on paginators
n2ygk Sep 7, 2018
5a8d67e
inadvertenly added a junked file
n2ygk Sep 7, 2018
7c8b044
PendingDeprecationWarnings
n2ygk Sep 8, 2018
929251f
Merge remote-tracking branch 'upstream/master' into remove-JSONAPI-pa…
Sep 12, 2018
1c810c0
Clarify deprecation warning of pagination classes
Sep 12, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ any parts of the framework not mentioned in the documentation should generally b
### Fixed

* Performance improvement when rendering relationships with `ModelSerializer`
* Do not show deprecation warning when user has implemented custom pagination class overwriting default values.


## [2.5.0] - 2018-07-11

Expand All @@ -40,6 +42,16 @@ any parts of the framework not mentioned in the documentation should generally b
### Deprecated

* Deprecate `PageNumberPagination` and `LimitOffsetPagination`. Use `JsonApiPageNumberPagination` and `JsonApiLimitOffsetPagination` instead.
* To retain deprecated values for `PageNumberPagination` and `LimitOffsetPagination` create new custom class like the following in your code base:
```python
class CustomPageNumberPagination(PageNumberPagination):
page_query_param = "page"
page_size_query_param = "page_size"

class CustomLimitOffsetPagination(LimitOffsetPagination):
max_limit = None
```
and adjust `REST_FRAMEWORK['DEFAULT_PAGINATION_CLASS']` setting accordingly.
* Deprecate `JSON_API_FORMAT_KEYS`, use `JSON_API_FORMAT_FIELD_NAMES`.

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ override ``settings.REST_FRAMEWORK``
'PAGE_SIZE': 10,
'EXCEPTION_HANDLER': 'rest_framework_json_api.exceptions.exception_handler',
'DEFAULT_PAGINATION_CLASS':
'rest_framework_json_api.pagination.JSONAPIPageNumberPagination',
'rest_framework_json_api.pagination.JsonApiPageNumberPagination',
'DEFAULT_PARSER_CLASSES': (
'rest_framework_json_api.parsers.JSONParser',
'rest_framework.parsers.FormParser',
Expand Down
35 changes: 22 additions & 13 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ REST_FRAMEWORK = {
'PAGE_SIZE': 10,
'EXCEPTION_HANDLER': 'rest_framework_json_api.exceptions.exception_handler',
'DEFAULT_PAGINATION_CLASS':
'rest_framework_json_api.pagination.JSONAPIPageNumberPagination',
'rest_framework_json_api.pagination.JsonApiPageNumberPagination',
'DEFAULT_PARSER_CLASSES': (
'rest_framework_json_api.parsers.JSONParser',
'rest_framework.parsers.FormParser',
Expand Down Expand Up @@ -50,6 +50,8 @@ DJA pagination is based on [DRF pagination](https://www.django-rest-framework.or
When pagination is enabled, the renderer will return a `meta` object with
record count and a `links` object with the next, previous, first, and last links.

Optional query parameters can also be provided to customize the page size or offset limit.

#### Configuring the Pagination Style

Pagination style can be set on a particular viewset with the `pagination_class` attribute or by default for all viewsets
Expand All @@ -59,35 +61,42 @@ You can configure fixed values for the page size or limit -- or allow the client
via query parameters.

Two pagination classes are available:
- `JSONAPIPageNumberPagination` breaks a response up into pages that start at a given page number
with a given size (number of items per page). It can be configured with the following attributes:
- `JsonApiPageNumberPagination` breaks a response up into pages that start at a given page number with a given size
(number of items per page). It can be configured with the following attributes:
- `page_query_param` (default `page[number]`)
- `page_size_query_param` (default `page[size]`) Set this to `None` if you don't want to allow the client
to specify the size.
- `page_size` (default `REST_FRAMEWORK['PAGE_SIZE']`) default number of items per page unless overridden by
`page_size_query_param`.
- `max_page_size` (default `100`) enforces an upper bound on the `page_size_query_param`.
Set it to `None` if you don't want to enforce an upper bound.
- `JSONAPILimitOffsetPagination` breaks a response up into pages that start from an item's offset
in the viewset for a given number of items (the limit).

- `JsonApiLimitOffsetPagination` breaks a response up into pages that start from an item's offset in the viewset for
a given number of items (the limit).
It can be configured with the following attributes:
- `offset_query_param` (default `page[offset]`).
- `limit_query_param` (default `page[limit]`).
- `default_limit` (default `REST_FRAMEWORK['PAGE_SIZE']`) is the default number of items per page unless
overridden by `limit_query_param`.
- `max_limit` (default `100`) enforces an upper bound on the limit.
Set it to `None` if you don't want to enforce an upper bound.


##### Examples
These examples show how to configure the parameters to use non-standard names and different limits:

```python
from rest_framework_json_api.pagination import JSONAPIPageNumberPagination, JSONAPILimitOffsetPagination
from rest_framework_json_api.pagination import JsonApiPageNumberPagination, JsonApiLimitOffsetPagination

class MyPagePagination(JSONAPIPageNumberPagination):
class MyPagePagination(JsonApiPageNumberPagination):
page_query_param = 'page_number'
page_size_query_param = 'page_size'
page_size_query_param = 'page_length'
page_size = 3
max_page_size = 1000

class MyLimitPagination(JSONAPILimitOffsetPagination):
class MyLimitPagination(JsonApiLimitOffsetPagination):
offset_query_param = 'offset'
limit_query_param = 'limit'
default_limit = 3
max_limit = None
```

Expand Down Expand Up @@ -146,7 +155,7 @@ If you are also using [`rest_framework.filters.SearchFilter`](https://django-res
(which performs single parameter searchs across multiple fields) you'll want to customize the name of the query
parameter for searching to make sure it doesn't conflict with a field name defined in the filterset.
The recommended value is: `search_param="filter[search]"` but just make sure it's
`filter[_something_]` to comply with the jsonapi spec requirement to use the filter
`filter[_something_]` to comply with the JSON:API spec requirement to use the filter
keyword. The default is "search" unless overriden.

The filter returns a `400 Bad Request` error for invalid filter query parameters as in this example
Expand Down Expand Up @@ -446,7 +455,7 @@ class OrderSerializer(serializers.ModelSerializer):

```

In the [JSON API spec](http://jsonapi.org/format/#document-resource-objects),
In the [JSON:API spec](http://jsonapi.org/format/#document-resource-objects),
relationship objects contain links to related objects. To make this work
on a serializer we need to tell the `ResourceRelatedField` about the
corresponding view. Use the `HyperlinkedModelSerializer` and instantiate
Expand Down Expand Up @@ -584,7 +593,7 @@ class OrderSerializer(serializers.HyperlinkedModelSerializer):
### RelationshipView
`rest_framework_json_api.views.RelationshipView` is used to build
relationship views (see the
[JSON API spec](http://jsonapi.org/format/#fetching-relationships)).
[JSON:API spec](http://jsonapi.org/format/#fetching-relationships)).
The `self` link on a relationship object should point to the corresponding
relationship view.

Expand Down
1 change: 1 addition & 0 deletions example/settings/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
JSON_API_FIELD_NAMES = 'camelize'
JSON_API_FORMAT_TYPES = 'camelize'
JSON_API_PLURALIZE_TYPES = True

REST_FRAMEWORK.update({
'PAGE_SIZE': 1,
})
64 changes: 51 additions & 13 deletions example/tests/unit/test_pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@

class TestLimitOffset:
"""
Unit tests for `pagination.JSONAPILimitOffsetPagination`.
Unit tests for `pagination.JsonApiLimitOffsetPagination`.
"""

def setup(self):
class ExamplePagination(pagination.JSONAPILimitOffsetPagination):
class ExamplePagination(pagination.JsonApiLimitOffsetPagination):
default_limit = 10
max_limit = 15

Expand Down Expand Up @@ -79,33 +79,71 @@ def test_valid_offset_limit(self):
assert queryset == list(range(offset + 1, next_offset + 1))
assert content == expected_content

@pytest.mark.xfail((sys.version_info.major, sys.version_info.minor) == (2, 7),
reason="python2.7 fails to generate DeprecationWarrning for unknown reason")
def test_limit_offset_deprecation(self):
with pytest.warns(DeprecationWarning) as record:
pagination.LimitOffsetPagination()
assert len(record) == 1
assert 'LimitOffsetPagination' in str(record[0].message)
assert 'LimitOffsetPagination is deprecated' in str(record[0].message)

class MyInheritedLimitOffsetPagination(pagination.LimitOffsetPagination):
"""
Inherit the default values
"""
pass

class MyOverridenLimitOffsetPagination(pagination.LimitOffsetPagination):
"""
Explicitly set max_limit to the "old" values.
"""
max_limit = None

def test_my_limit_offset_deprecation(self):
with pytest.warns(DeprecationWarning) as record:
pagination.JsonApiLimitOffsetPagination()
self.MyInheritedLimitOffsetPagination()
assert len(record) == 1
assert 'JsonApiLimitOffsetPagination' in str(record[0].message)
assert 'LimitOffsetPagination is deprecated' in str(record[0].message)

with pytest.warns(None) as record:
self.MyOverridenLimitOffsetPagination()
assert len(record) == 0


# TODO: This test fails under py27 but it's not clear why so just leave it out for now.
@pytest.mark.xfail((sys.version_info.major, sys.version_info.minor) == (2, 7),
reason="python2.7 fails for unknown reason")
class TestPageNumber:
"""
Unit tests for `pagination.JSONAPIPageNumberPagination`.
TODO: add unit tests for changing query parameter names, limits, etc.
Unit tests for `pagination.JsonApiPageNumberPagination`.
"""

@pytest.mark.xfail((sys.version_info.major, sys.version_info.minor) == (2, 7),
reason="python2.7 fails to generate DeprecationWarrning for unknown reason")
def test_page_number_deprecation(self):
with pytest.warns(DeprecationWarning) as record:
pagination.PageNumberPagination()
assert len(record) == 1
assert 'PageNumberPagination' in str(record[0].message)
assert 'PageNumberPagination is deprecated' in str(record[0].message)

class MyInheritedPageNumberPagination(pagination.PageNumberPagination):
"""
Inherit the default values
"""
pass

class MyOverridenPageNumberPagination(pagination.PageNumberPagination):
"""
Explicitly set page_query_param and page_size_query_param to the "old" values.
"""
page_query_param = "page"
page_size_query_param = "page_size"

@pytest.mark.xfail((sys.version_info.major, sys.version_info.minor) == (2, 7),
reason="python2.7 fails to generate DeprecationWarrning for unknown reason")
def test_my_page_number_deprecation(self):
with pytest.warns(DeprecationWarning) as record:
pagination.JsonApiPageNumberPagination()
self.MyInheritedPageNumberPagination()
assert len(record) == 1
assert 'JsonApiPageNumberPagination' in str(record[0].message)
assert 'PageNumberPagination is deprecated' in str(record[0].message)

with pytest.warns(None) as record:
self.MyOverridenPageNumberPagination()
assert len(record) == 0
6 changes: 3 additions & 3 deletions example/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def get_object(self):
return super(BlogViewSet, self).get_object()


class JSONAPIViewSet(ModelViewSet):
class JsonApiViewSet(ModelViewSet):
"""
This is an example on how to configure DRF-jsonapi from
within a class. It allows using DRF-jsonapi alongside
Expand All @@ -59,12 +59,12 @@ def handle_exception(self, exc):
exc.status_code = HTTP_422_UNPROCESSABLE_ENTITY
# exception handler can't be set on class so you have to
# override the error response in this method
response = super(JSONAPIViewSet, self).handle_exception(exc)
response = super(JsonApiViewSet, self).handle_exception(exc)
context = self.get_exception_handler_context()
return format_drf_errors(response, context, exc)


class BlogCustomViewSet(JSONAPIViewSet):
class BlogCustomViewSet(JsonApiViewSet):
queryset = Blog.objects.all()
serializer_class = BlogSerializer

Expand Down
80 changes: 34 additions & 46 deletions rest_framework_json_api/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
from rest_framework.views import Response


class JSONAPIPageNumberPagination(PageNumberPagination):
class JsonApiPageNumberPagination(PageNumberPagination):
"""
A json-api compatible pagination format
A json-api compatible pagination format.
Use a private name for the implementation because the public name is pending deprecation.
"""
page_query_param = 'page[number]'
page_size_query_param = 'page[size]'
Expand Down Expand Up @@ -50,11 +51,13 @@ def get_paginated_response(self, data):
})


class JSONAPILimitOffsetPagination(LimitOffsetPagination):
class JsonApiLimitOffsetPagination(LimitOffsetPagination):
"""
A limit/offset based style. For example:
http://api.example.org/accounts/?page[limit]=100
http://api.example.org/accounts/?page[offset]=400&page[limit]=100

Use a private name for the implementation because the public name is pending deprecation.
"""
limit_query_param = 'page[limit]'
offset_query_param = 'page[offset]'
Expand Down Expand Up @@ -100,63 +103,48 @@ def get_paginated_response(self, data):
})


class JsonApiPageNumberPagination(JSONAPIPageNumberPagination):
class PageNumberPagination(JsonApiPageNumberPagination):
"""
Deprecated due to desire to use `JSONAPI` prefix for all classes.
A soon-to-be-changed paginator that uses non-JSON:API query parameters (default:
'page' and 'page_size' instead of 'page[number]' and 'page[size]').
"""
page_query_param = 'page'
page_size_query_param = 'page_size'

def __init__(self):
warnings.warn(
'JsonApiPageNumberPagination is deprecated. Use JSONAPIPageNumberPagination '
'or create custom pagination. See '
'https://django-rest-framework-json-api.readthedocs.io/en/stable/usage.html#pagination',
DeprecationWarning)
super(JsonApiPageNumberPagination, self).__init__()


class PageNumberPagination(JSONAPIPageNumberPagination):
"""
Deprecated paginator that uses different query parameters
"""
page_query_param = 'page'
page_size_query_param = 'page_size'
if type(self) == PageNumberPagination:
warn = self.page_query_param == 'page' or self.page_size_query_param == 'page_size'
else: # inherited class doesn't override the attributes?
warn = ('page_query_param' not in type(self).__dict__ or
'page_size_query_param' not in type(self).__dict__)
if warn:
warnings.warn(
'PageNumberPagination is deprecated use JsonApiPageNumberPagination instead. '
'If you want to retain current defaults you will need to implement custom '
'pagination class explicitly setting `page_query_param = "page"` and '
'`page_size_query_param = "page_size"`. '
'See changelog for more details.',
DeprecationWarning)

def __init__(self):
warnings.warn(
'PageNumberPagination is deprecated. Use JSONAPIPageNumberPagination '
'or create custom pagination. See '
'https://django-rest-framework-json-api.readthedocs.io/en/stable/usage.html#pagination',
DeprecationWarning)
super(PageNumberPagination, self).__init__()


class JsonApiLimitOffsetPagination(JSONAPILimitOffsetPagination):
"""
Deprecated due to desire to use `JSONAPI` prefix for all classes.
"""
max_limit = None

def __init__(self):
warnings.warn(
'JsonApiLimitOffsetPagination is deprecated. Use JSONAPILimitOffsetPagination '
'or create custom pagination. See '
'https://django-rest-framework-json-api.readthedocs.io/en/stable/usage.html#pagination',
DeprecationWarning)
super(JsonApiLimitOffsetPagination, self).__init__()


class LimitOffsetPagination(JSONAPILimitOffsetPagination):
class LimitOffsetPagination(JsonApiLimitOffsetPagination):
"""
Deprecated paginator that uses a different max_limit
"""
max_limit = None

def __init__(self):
warnings.warn(
'LimitOffsetPagination is deprecated. Use JSONAPILimitOffsetPagination '
'or create custom pagination. See '
'https://django-rest-framework-json-api.readthedocs.io/en/stable/usage.html#pagination',
DeprecationWarning)
if type(self) == LimitOffsetPagination:
warn = self.max_limit is None
else:
warn = 'max_limit' not in type(self).__dict__
if warn:
warnings.warn(
'LimitOffsetPagination is deprecated use JsonApiLimitOffsetPagination instead. '
'If you want to retain current defaults you will need to implement custom '
'pagination class explicitly setting `max_limit = None`. '
'See changelog for more details.',
DeprecationWarning)
super(LimitOffsetPagination, self).__init__()