Skip to content

Commit e4594e0

Browse files
committed
Merge pull request #194 from ZEROFAIL/docs_related_fields
Document usage of related fields and RelationshipView
2 parents 63d7882 + 3f719ac commit e4594e0

File tree

1 file changed

+166
-0
lines changed

1 file changed

+166
-0
lines changed

‎docs/usage.md

+166
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ record count and a `links` object with the next, previous, first, and last links
3434
Pages can be selected with the `page` GET parameter. Page size can be controlled
3535
per request via the `PAGINATE_BY_PARAM` query parameter (`page_size` by default).
3636

37+
### Serializers
38+
39+
It is recommended to import the base serializer classes from this package
40+
rather than from vanilla DRF. For example,
41+
42+
```python
43+
from rest_framework_json_api import serializers
44+
45+
class MyModelSerializer(serializers.ModelSerializers):
46+
# ...
47+
```
48+
3749
### Setting the resource_name
3850

3951
You may manually set the `resource_name` property on views, serializers, or
@@ -248,6 +260,160 @@ When set to pluralize:
248260
Both `JSON_API_PLURALIZE_RELATION_TYPE` and `JSON_API_FORMAT_RELATION_KEYS` can be combined to
249261
achieve different results.
250262

263+
### Related fields
264+
265+
Because of the additional structure needed to represent relationships in JSON
266+
API, this package provides the `ResourceRelatedField` for serializers, which
267+
works similarly to `PrimaryKeyRelatedField`. By default,
268+
`rest_framework_json_api.serializers.ModelSerializer` will use this for
269+
related fields automatically. It can be instantiated explicitly as in the
270+
following example:
271+
272+
```python
273+
from rest_framework_json_api import serializers
274+
from rest_framework_json_api.relations import ResourceRelatedField
275+
276+
from myapp.models import Order, LineItem, Customer
277+
278+
279+
class OrderSerializer(serializers.ModelSerializer):
280+
class Meta:
281+
model = Order
282+
283+
line_items = ResourceRelatedField(
284+
queryset=LineItem.objects,
285+
many=True # necessary for M2M fields & reverse FK fields
286+
)
287+
288+
customer = ResourceRelatedField(
289+
queryset=Customer.objects # queryset argument is required
290+
) # except when read_only=True
291+
292+
```
293+
294+
In the [JSON API spec](http://jsonapi.org/format/#document-resource-objects),
295+
relationship objects contain links to related objects. To make this work
296+
on a serializer we need to tell the `ResourceRelatedField` about the
297+
corresponding view. Use the `HyperlinkedModelSerializer` and instantiate
298+
the `ResourceRelatedField` with the relevant keyword arguments:
299+
300+
```python
301+
from rest_framework_json_api import serializers
302+
from rest_framework_json_api.relations import ResourceRelatedField
303+
304+
from myapp.models import Order, LineItem, Customer
305+
306+
307+
class OrderSerializer(serializers.ModelSerializer):
308+
class Meta:
309+
model = Order
310+
311+
line_items = ResourceRelatedField(
312+
queryset=LineItem.objects,
313+
many=True,
314+
related_link_view_name='order-lineitems-list',
315+
related_link_url_kwarg='order_pk',
316+
self_link_view_name='order_relationships'
317+
)
318+
319+
customer = ResourceRelatedField(
320+
queryset=Customer.objects,
321+
related_link_view-name='order-customer-detail',
322+
related_link_url_kwarg='order_pk',
323+
self_link_view_name='order-relationships'
324+
)
325+
```
326+
327+
* `related_link_view_name` is the name of the route for the related
328+
view.
329+
330+
* `related_link_url_kwarg` is the keyword argument that will be passed
331+
to the view that identifies the 'parent' object, so that the results
332+
can be filtered to show only those objects related to the 'parent'.
333+
334+
* `self_link_view_name` is the name of the route for the `RelationshipView`
335+
(see below).
336+
337+
In this example, `reverse('order-lineitems-list', kwargs={'order_pk': 3}`
338+
should resolve to something like `/orders/3/lineitems`, and that route
339+
should instantiate a view or viewset for `LineItem` objects that accepts
340+
a keword argument `order_pk`. The
341+
[drf-nested-routers](https://github.com/alanjds/drf-nested-routers) package
342+
is useful for defining such nested routes in your urlconf.
343+
344+
The corresponding viewset for the `line-items-list` route in the above example
345+
might look like the following. Note that in the typical use case this would be
346+
the same viewset used for the `/lineitems` endpoints; when accessed through
347+
the nested route `/orders/<order_pk>/lineitems` the queryset is filtered using
348+
the `order_pk` keyword argument to include only the lineitems related to the
349+
specified order.
350+
351+
```python
352+
from rest_framework import viewsets
353+
354+
from myapp.models import LineItem
355+
from myapp.serializers import LineItemSerializer
356+
357+
358+
class LineItemViewSet(viewsets.ModelViewSet):
359+
queryset = LineItem.objects
360+
serializer_class = LineItemSerializer
361+
362+
def get_queryset(self):
363+
queryset = self.queryset
364+
365+
# if this viewset is accessed via the 'order-lineitems-list' route,
366+
# it wll have been passed the `order_pk` kwarg and the queryset
367+
# needs to be filtered accordingly; if it was accessed via the
368+
# unnested '/lineitems' route, the queryset should include all LineItems
369+
if 'order_pk' in self.kwargs:
370+
order_pk = self.kwargs['order_pk']
371+
queryset = queryset.filter(order__pk=order_pk])
372+
373+
return queryset
374+
```
375+
376+
### RelationshipView
377+
`rest_framework_json_api.views.RelationshipView` is used to build
378+
relationship views (see the
379+
[JSON API spec](http://jsonapi.org/format/#fetching-relationships)).
380+
The `self` link on a relationship object should point to the corresponding
381+
relationship view.
382+
383+
The relationship view is fairly simple because it only serializes
384+
[Resource Identifier Objects](http://jsonapi.org/format/#document-resource-identifier-objects)
385+
rather than full resource objects. In most cases the following is sufficient:
386+
387+
```python
388+
from rest_framework_json_api.views import RelationshipView
389+
390+
from myapp.models import Order
391+
392+
393+
class OrderRelationshipView(RelationshipView):
394+
queryset = Order.objects
395+
396+
```
397+
398+
The urlconf would need to contain a route like the following:
399+
400+
```python
401+
url(
402+
regex=r'^orders/(?P<pk>[^/.]+/relationships/(?P<related_field>[^/.]+)$',
403+
view=OrderRelationshipView.as_view(),
404+
name='order-relationships'
405+
)
406+
```
407+
408+
The `related_field` kwarg specifies which relationship to use, so
409+
if we are interested in the relationship represented by the related
410+
model field `Order.line_items` on the Order with pk 3, the url would be
411+
`/order/3/relationships/line_items`. On `HyperlinkedModelSerializer`, the
412+
`ResourceRelatedField` will construct the url based on the provided
413+
`self_link_view_name` keyword argument, which should match the `name=`
414+
provided in the urlconf, and will use the name of the field for the
415+
`related_field` kwarg.
416+
251417
### Meta
252418

253419
You may add metadata to the rendered json in two different ways: `meta_fields` and `get_root_meta`.

0 commit comments

Comments
 (0)