Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 87108d4

Browse files
authored
Ensured that include param is properly underscored (#1283)
nsured that interpreting `include` query parameter is done in internal Python naming.
1 parent 0394cf9 commit 87108d4

File tree

6 files changed

+43
-9
lines changed

6 files changed

+43
-9
lines changed

‎CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ any parts of the framework not mentioned in the documentation should generally b
1515
* Added support for Django REST framework 3.16.
1616
* Added support for Django 5.2.
1717

18+
### Fixed
19+
20+
* Ensured that interpreting `include` query parameter is done in internal Python naming.
21+
This adds full support for using multipart field names for includes while configuring `JSON_API_FORMAT_FIELD_NAMES`.
22+
1823
### Removed
1924

2025
* Removed support for Python 3.8.

‎rest_framework_json_api/renderers.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from collections import defaultdict
77
from collections.abc import Iterable
88

9-
import inflection
109
from django.db.models import Manager
1110
from django.template import loader
1211
from django.utils.encoding import force_str
@@ -277,9 +276,6 @@ def extract_included(
277276
current_serializer, "included_serializers", dict()
278277
)
279278
included_resources = copy.copy(included_resources)
280-
included_resources = [
281-
inflection.underscore(value) for value in included_resources
282-
]
283279

284280
for field_name, field in iter(fields.items()):
285281
# Skip URL field

‎rest_framework_json_api/serializers.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from collections.abc import Mapping
22

3-
import inflection
43
from django.core.exceptions import ObjectDoesNotExist
54
from django.db.models.query import QuerySet
65
from django.utils.module_loading import import_string as import_class_from_dotted_path
@@ -129,7 +128,7 @@ def validate_path(serializer_class, field_path, path):
129128
serializers = getattr(serializer_class, "included_serializers", None)
130129
if serializers is None:
131130
raise ParseError("This endpoint does not support the include parameter")
132-
this_field_name = inflection.underscore(field_path[0])
131+
this_field_name = field_path[0]
133132
this_included_serializer = serializers.get(this_field_name)
134133
if this_included_serializer is None:
135134
raise ParseError(

‎rest_framework_json_api/utils.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,18 @@ def get_resource_id(resource_instance, resource):
316316

317317

318318
def get_included_resources(request, serializer=None):
319-
"""Build a list of included resources."""
319+
"""
320+
Build a list of included resources.
321+
322+
This method ensures that returned includes are in Python internally used
323+
format.
324+
"""
320325
include_resources_param = request.query_params.get("include") if request else None
321326
if include_resources_param:
322-
return include_resources_param.split(",")
327+
return [
328+
undo_format_field_name(include)
329+
for include in include_resources_param.split(",")
330+
]
323331
else:
324332
return get_default_included_resources_from_serializer(serializer)
325333

‎tests/conftest.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import pytest
2-
from rest_framework.test import APIClient
2+
from rest_framework.test import APIClient, APIRequestFactory
33

44
from tests.models import (
55
BasicModel,
@@ -98,3 +98,8 @@ def nested_related_source(
9898
@pytest.fixture
9999
def client():
100100
return APIClient()
101+
102+
103+
@pytest.fixture
104+
def rf():
105+
return APIRequestFactory()

‎tests/test_utils.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from rest_framework import status
33
from rest_framework.fields import Field
44
from rest_framework.generics import GenericAPIView
5+
from rest_framework.request import Request
56
from rest_framework.response import Response
67
from rest_framework.views import APIView
78

@@ -13,6 +14,7 @@
1314
format_link_segment,
1415
format_resource_type,
1516
format_value,
17+
get_included_resources,
1618
get_related_resource_type,
1719
get_resource_id,
1820
get_resource_name,
@@ -456,3 +458,22 @@ def test_get_resource_id(resource_instance, resource, expected):
456458
)
457459
def test_format_error_object(message, pointer, response, result):
458460
assert result == format_error_object(message, pointer, response)
461+
462+
463+
@pytest.mark.parametrize(
464+
"format_type,include_param,expected_includes",
465+
[
466+
("dasherize", "author-bio", ["author_bio"]),
467+
("dasherize", "author-bio,author-type", ["author_bio", "author_type"]),
468+
("dasherize", "author-bio.author-type", ["author_bio.author_type"]),
469+
("camelize", "authorBio", ["author_bio"]),
470+
],
471+
)
472+
def test_get_included_resources(
473+
rf, include_param, expected_includes, format_type, settings
474+
):
475+
settings.JSON_API_FORMAT_FIELD_NAMES = format_type
476+
477+
request = Request(rf.get("/test/", {"include": include_param}))
478+
includes = get_included_resources(request)
479+
assert includes == expected_includes

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /