Skip to content

Document usage of related fields and RelationshipView #194

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 2 commits into from
Apr 11, 2016
Merged
Changes from all commits
Commits
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
166 changes: 166 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ record count and a `links` object with the next, previous, first, and last links
Pages can be selected with the `page` GET parameter. Page size can be controlled
per request via the `PAGINATE_BY_PARAM` query parameter (`page_size` by default).

### Serializers

It is recommended to import the base serializer classes from this package
rather than from vanilla DRF. For example,

```python
from rest_framework_json_api import serializers

class MyModelSerializer(serializers.ModelSerializers):
# ...
```

### Setting the resource_name

You may manually set the `resource_name` property on views or serializers to
Expand Down Expand Up @@ -226,6 +238,160 @@ When set to pluralize:
Both `JSON_API_PLURALIZE_RELATION_TYPE` and `JSON_API_FORMAT_RELATION_KEYS` can be combined to
achieve different results.

### Related fields

Because of the additional structure needed to represent relationships in JSON
API, this package provides the `ResourceRelatedField` for serializers, which
works similarly to `PrimaryKeyRelatedField`. By default,
`rest_framework_json_api.serializers.ModelSerializer` will use this for
related fields automatically. It can be instantiated explicitly as in the
following example:

```python
from rest_framework_json_api import serializers
from rest_framework_json_api.relations import ResourceRelatedField

from myapp.models import Order, LineItem, Customer


class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order

line_items = ResourceRelatedField(
queryset=LineItem.objects,
many=True # necessary for M2M fields & reverse FK fields
)

customer = ResourceRelatedField(
queryset=Customer.objects # queryset argument is required
) # except when read_only=True

```

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
the `ResourceRelatedField` with the relevant keyword arguments:

```python
from rest_framework_json_api import serializers
from rest_framework_json_api.relations import ResourceRelatedField

from myapp.models import Order, LineItem, Customer


class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order

line_items = ResourceRelatedField(
queryset=LineItem.objects,
many=True,
related_link_view_name='order-lineitems-list',
related_link_url_kwarg='order_pk',
self_link_view_name='order_relationships'
)

customer = ResourceRelatedField(
queryset=Customer.objects,
related_link_view-name='order-customer-detail',
related_link_url_kwarg='order_pk',
self_link_view_name='order-relationships'
)
```

* `related_link_view_name` is the name of the route for the related
view.

* `related_link_url_kwarg` is the keyword argument that will be passed
to the view that identifies the 'parent' object, so that the results
can be filtered to show only those objects related to the 'parent'.

* `self_link_view_name` is the name of the route for the `RelationshipView`
(see below).

In this example, `reverse('order-lineitems-list', kwargs={'order_pk': 3}`
should resolve to something like `/orders/3/lineitems`, and that route
should instantiate a view or viewset for `LineItem` objects that accepts
a keword argument `order_pk`. The
[drf-nested-routers](https://github.com/alanjds/drf-nested-routers) package
is useful for defining such nested routes in your urlconf.

The corresponding viewset for the `line-items-list` route in the above example
might look like the following. Note that in the typical use case this would be
the same viewset used for the `/lineitems` endpoints; when accessed through
the nested route `/orders/<order_pk>/lineitems` the queryset is filtered using
the `order_pk` keyword argument to include only the lineitems related to the
specified order.

```python
from rest_framework import viewsets

from myapp.models import LineItem
from myapp.serializers import LineItemSerializer


class LineItemViewSet(viewsets.ModelViewSet):
queryset = LineItem.objects
serializer_class = LineItemSerializer

def get_queryset(self):
queryset = self.queryset

# if this viewset is accessed via the 'order-lineitems-list' route,
# it wll have been passed the `order_pk` kwarg and the queryset
# needs to be filtered accordingly; if it was accessed via the
# unnested '/lineitems' route, the queryset should include all LineItems
if 'order_pk' in self.kwargs:
order_pk = self.kwargs['order_pk']
queryset = queryset.filter(order__pk=order_pk])

return queryset
```

### RelationshipView
`rest_framework_json_api.views.RelationshipView` is used to build
relationship views (see the
[JSON API spec](http://jsonapi.org/format/#fetching-relationships)).
The `self` link on a relationship object should point to the corresponding
relationship view.

The relationship view is fairly simple because it only serializes
[Resource Identifier Objects](http://jsonapi.org/format/#document-resource-identifier-objects)
rather than full resource objects. In most cases the following is sufficient:

```python
from rest_framework_json_api.views import RelationshipView

from myapp.models import Order


class OrderRelationshipView(RelationshipView):
queryset = Order.objects

```

The urlconf would need to contain a route like the following:

```python
url(
regex=r'^orders/(?P<pk>[^/.]+/relationships/(?P<related_field>[^/.]+)$',
view=OrderRelationshipView.as_view(),
name='order-relationships'
)
```

The `related_field` kwarg specifies which relationship to use, so
if we are interested in the relationship represented by the related
model field `Order.line_items` on the Order with pk 3, the url would be
`/order/3/relationships/line_items`. On `HyperlinkedModelSerializer`, the
`ResourceRelatedField` will construct the url based on the provided
`self_link_view_name` keyword argument, which should match the `name=`
provided in the urlconf, and will use the name of the field for the
`related_field` kwarg.

### Meta

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