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 a5df955

Browse files
Properly support formatting of link segments in related urls (#897)
1 parent 7d2970a commit a5df955

File tree

5 files changed

+44
-7
lines changed

5 files changed

+44
-7
lines changed

‎CHANGELOG.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ any parts of the framework not mentioned in the documentation should generally b
1919

2020
* Allow `get_serializer_class` to be overwritten when using related urls without defining `serializer_class` fallback
2121
* Preserve field names when no formatting is configured.
22+
* Properly support `JSON_API_FORMAT_RELATED_LINKS` setting in related urls. In case you want to use `dasherize` for formatting links make sure that your url pattern matches dashes as well like following example:
23+
```
24+
url(r'^orders/(?P<pk>[^/.]+)/(?P<related_field>[-\w]+)/$',
25+
OrderViewSet.as_view({'get': 'retrieve_related'}),
26+
name='order-related'),
27+
```
28+
2229

2330
### Deprecated
2431

‎docs/usage.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,11 @@ For example, with a serializer property `created_by` and with `'dasherize'` form
515515

516516
The relationship name is formatted by the `JSON_API_FORMAT_FIELD_NAMES` setting, but the URL segments are formatted by the `JSON_API_FORMAT_RELATED_LINKS` setting.
517517

518+
<div class="warning">
519+
<strong>Note:</strong>
520+
When using this setting make sure that your url pattern matches the formatted url segement.
521+
</div>
522+
518523
### Related fields
519524

520525
#### ResourceRelatedField
@@ -702,7 +707,7 @@ All you need is just add to `urls.py`:
702707
url(r'^orders/(?P<pk>[^/.]+)/$',
703708
OrderViewSet.as_view({'get': 'retrieve'}),
704709
name='order-detail'),
705-
url(r'^orders/(?P<pk>[^/.]+)/(?P<related_field>\w+)/$',
710+
url(r'^orders/(?P<pk>[^/.]+)/(?P<related_field>[-\w]+)/$',
706711
OrderViewSet.as_view({'get': 'retrieve_related'}),
707712
name='order-related'),
708713
```
@@ -775,7 +780,7 @@ The urlconf would need to contain a route like the following:
775780

776781
```python
777782
url(
778-
regex=r'^orders/(?P<pk>[^/.]+)/relationships/(?P<related_field>[^/.]+)$',
783+
regex=r'^orders/(?P<pk>[^/.]+)/relationships/(?P<related_field>[-/w]+)$',
779784
view=OrderRelationshipView.as_view(),
780785
name='order-relationships'
781786
)

‎example/tests/test_views.py‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import json
22
from datetime import datetime
33

4-
from django.test import RequestFactory
4+
from django.test import RequestFactory, override_settings
55
from django.utils import timezone
66
from rest_framework import status
77
from rest_framework.decorators import action
@@ -92,6 +92,18 @@ def test_get_blog_relationship_entry_set(self):
9292

9393
assert response.data == expected_data
9494

95+
@override_settings(JSON_API_FORMAT_RELATED_LINKS="dasherize")
96+
def test_get_blog_relationship_entry_set_with_formatted_link(self):
97+
response = self.client.get(
98+
"/blogs/{}/relationships/entry-set".format(self.blog.id)
99+
)
100+
expected_data = [
101+
{"type": format_resource_type("Entry"), "id": str(self.first_entry.id)},
102+
{"type": format_resource_type("Entry"), "id": str(self.second_entry.id)},
103+
]
104+
105+
assert response.data == expected_data
106+
95107
def test_put_entry_relationship_blog_returns_405(self):
96108
url = "/entries/{}/relationships/blog".format(self.first_entry.id)
97109
response = self.client.put(url, data={})
@@ -507,6 +519,17 @@ def test_retrieve_related_None(self):
507519
self.assertEqual(resp.status_code, 200)
508520
self.assertEqual(resp.json(), {"data": None})
509521

522+
@override_settings(JSON_API_FORMAT_RELATED_LINKS="dasherize")
523+
def test_retrieve_related_with_formatted_link(self):
524+
first_entry = EntryFactory(authors=(self.author,))
525+
526+
kwargs = {"pk": self.author.pk, "related_field": "first-entry"}
527+
url = reverse("author-related", kwargs=kwargs)
528+
resp = self.client.get(url)
529+
530+
self.assertEqual(resp.status_code, 200)
531+
self.assertEqual(resp.json()["data"]["id"], str(first_entry.id))
532+
510533

511534
class TestValidationErrorResponses(TestBase):
512535
def test_if_returns_error_on_empty_post(self):

‎example/urls_test.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,17 @@
7878
name="entry-featured",
7979
),
8080
re_path(
81-
r"^authors/(?P<pk>[^/.]+)/(?P<related_field>\w+)/$",
81+
r"^authors/(?P<pk>[^/.]+)/(?P<related_field>[-\w]+)/$",
8282
AuthorViewSet.as_view({"get": "retrieve_related"}),
8383
name="author-related",
8484
),
8585
re_path(
86-
r"^entries/(?P<pk>[^/.]+)/relationships/(?P<related_field>\w+)$",
86+
r"^entries/(?P<pk>[^/.]+)/relationships/(?P<related_field>[\-\w]+)$",
8787
EntryRelationshipView.as_view(),
8888
name="entry-relationships",
8989
),
9090
re_path(
91-
r"^blogs/(?P<pk>[^/.]+)/relationships/(?P<related_field>\w+)$",
91+
r"^blogs/(?P<pk>[^/.]+)/relationships/(?P<related_field>[^/.]+)$",
9292
BlogRelationshipView.as_view(),
9393
name="blog-relationships",
9494
),

‎rest_framework_json_api/views.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def get_related_serializer_class(self):
157157
parent_serializer_class = self.get_serializer_class()
158158

159159
if "related_field" in self.kwargs:
160-
field_name = self.kwargs["related_field"]
160+
field_name = self.get_related_field_name()
161161

162162
# Try get the class from related_serializers
163163
if hasattr(parent_serializer_class, "related_serializers"):
@@ -402,6 +402,8 @@ def get_related_instance(self):
402402

403403
def get_related_field_name(self):
404404
field_name = self.kwargs["related_field"]
405+
field_name = undo_format_link_segment(field_name)
406+
405407
if field_name in self.field_name_mapping:
406408
return self.field_name_mapping[field_name]
407409
return field_name

0 commit comments

Comments
(0)

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