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