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 b9ccd9d

Browse files
committed
v2.0.0-beta.2 -> v2.0.0
* docs: note about importing serializers * Document ResourceRelatedField and RelationshipView * Updated pip install instructions for 2.0.0-beta.2 * Add LimitOffsetPagination * Dont let the offset go into negative space * Add basic unit test for LimitOffsetPagination * Support deeply nested includes Allow skipping of intermediate included models * Add current tox.ini directory to PYTHONPATH in order to use imports form there Fix regression on PY3 caused by unicode_literals * [FEATURE]: support using get_serializer_class on view * fixed extract_root_meta for lists * Fixed get_resource_name in case of non-model backed serializer. Closes #219 * ResourceRelatedField now accepts serializer methods when many=True * Rename "suggested" posts to "featured" so we can use suggested as many=True * Updated SerializerMethodResourceRelatedField to allow many=True Issue #151 Closes #220 * Correct error responses for projects with different DRF-configurations (#222) * [#214] Add error messages tests. * [#214] Extract formatting DRF errors. * Add example view with custom handle_exception. * Use HTTP 422 for validation error responses. * Add full example of class-configured json api view. * Fixed naming that suggested settings were used to inflect relationship names. JSON_API_FORMAT_RELATION_NAME actually inflected the `type` instead. The relation name is not changable at this time although if it woudl be useful to someone it would be fine to implement it. Closes #136. * Updated changelog * Added a doc note to prefer setting resource_name on serializers or models. Closes #207 * Added get_related_field_name method to RelationshipView * Added get_related_field_name method to RelationshipView * Added docs about field_name_mapping * Updated the readme for testing (#234) * Allow exception handler to be used by normal DRF views: (#233) * Add top-level 'errors' object to non-JSON-API responses * Allow configuring the exception handler to be used _only_ in JSON API views or uniformly across all views * Fix included resource type inconsistency (#229) When setting `resource_name = None`, the related instance's resource name is used in `relationships`, but `None` is used in `included`. This is related to #94 and #124 * Fixes #230. Keep write only fields from having an attribute key * Release v2.0.0 * Update setup.py to classify as production/stable
1 parent 8c4db64 commit b9ccd9d

31 files changed

+851
-209
lines changed

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@ pip-delete-this-directory.txt
3030

3131
# Tox
3232
.tox/
33+
34+
# VirtualEnv
35+
.venv/

‎CHANGELOG.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11

2+
v2.0.0
3+
4+
* Fixed bug where write_only fields still had their keys rendered
5+
* Exception handler can now easily be used on DRF-JA views alongside regular DRF views
6+
* Added `get_related_field_name` for views subclassing RelationshipView to override
7+
* Renamed `JSON_API_FORMAT_RELATION_KEYS` to `JSON_API_FORMAT_TYPES` to match what it was actually doing
8+
* Renamed `JSON_API_PLURALIZE_RELATION_TYPE` to `JSON_API_PLURALIZE_TYPES`
9+
* Documented ResourceRelatedField and RelationshipView
10+
* Added LimitOffsetPagination
11+
* Support deeply nested `?includes=foo.bar.baz` without returning intermediate models (bar)
12+
* Allow a view's serializer_class to be fetched at runtime via `get_serializer_class`
13+
* Added support for `get_root_meta` on list serializers
14+
15+
216
v2.0.0-beta.2
317

418
* Added JSONAPIMeta class option to models for overriding `resource_name`. #197

‎README.rst‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ From PyPI
8080

8181
::
8282

83-
$ pip install djangorestframework-jsonapi==2.0.0-beta.1
83+
$ pip install djangorestframework-jsonapi
8484

8585

8686
From Source
@@ -107,9 +107,14 @@ Browse to http://localhost:8000
107107
Running Tests
108108
^^^^^^^^^^^^^
109109

110+
It is recommended to create a virtualenv for testing. Assuming it is already
111+
installed and activated:
112+
110113
::
111114

112-
$ python runtests.py
115+
$ pip install -e .
116+
$ pip install -r requirements-development.txt
117+
$ py.test
113118

114119

115120
-----

‎docs/api.md‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Gathers the data from serializer fields specified in `meta_fields` and adds it t
3838

3939
#### extract_root_meta
4040

41-
`extract_root_meta(serializer, resource, meta)`
41+
`extract_root_meta(serializer, resource)`
4242

4343
Calls a `get_root_meta` function on a serializer, if it exists.
4444

@@ -47,4 +47,3 @@ Calls a `get_root_meta` function on a serializer, if it exists.
4747
`build_json_resource_obj(fields, resource, resource_instance, resource_name)`
4848

4949
Builds the resource object (type, id, attributes) and extracts relationships.
50-

‎docs/usage.md‎

Lines changed: 195 additions & 13 deletions
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
@@ -75,7 +87,10 @@ class Me(models.Model):
7587
If you set the `resource_name` on a combination of model, serializer, or view
7688
in the same hierarchy, the name will be resolved as following: view >
7789
serializer > model. (Ex: A view `resource_name` will always override a
78-
`resource_name` specified on a serializer or model)
90+
`resource_name` specified on a serializer or model). Setting the `resource_name`
91+
on the view should be used sparingly as serializers and models are shared between
92+
multiple endpoints. Setting the `resource_name` on views may result in a different
93+
`type` being set depending on which endpoint the resource is fetched from.
7994

8095

8196
### Inflecting object and relation keys
@@ -143,20 +158,20 @@ Example - With format conversion set to `dasherize`:
143158
}
144159
```
145160

146-
#### Relationship types
161+
#### Types
147162

148-
A similar option to JSON\_API\_FORMAT\_RELATION\_KEYS can be set for the relationship names:
163+
A similar option to JSON\_API\_FORMAT\_KEYS can be set for the types:
149164

150165
``` python
151-
JSON_API_FORMAT_RELATION_KEYS = 'dasherize'
166+
JSON_API_FORMAT_TYPES = 'dasherize'
152167
```
153168

154169
Example without format conversion:
155170

156171
``` js
157172
{
158173
"data": [{
159-
"type": "identities",
174+
"type": "blog_identity",
160175
"id": 3,
161176
"attributes": {
162177
...
@@ -179,7 +194,7 @@ When set to dasherize:
179194
``` js
180195
{
181196
"data": [{
182-
"type": "identities",
197+
"type": "blog-identity",
183198
"id": 3,
184199
"attributes": {
185200
...
@@ -198,7 +213,7 @@ When set to dasherize:
198213
It is also possible to pluralize the types like so:
199214

200215
```python
201-
JSON_API_PLURALIZE_RELATION_TYPE = True
216+
JSON_API_PLURALIZE_TYPES = True
202217
```
203218
Example without pluralization:
204219

@@ -245,8 +260,168 @@ When set to pluralize:
245260
}
246261
```
247262

248-
Both `JSON_API_PLURALIZE_RELATION_TYPE` and `JSON_API_FORMAT_RELATION_KEYS` can be combined to
249-
achieve different results.
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+
Also we can override `related_field` in the url. Let's say we want the url to be:
417+
`/order/3/relationships/order_items` - all we need to do is just add `field_name_mapping`
418+
dict to the class:
419+
```python
420+
field_name_mapping = {
421+
'line_items': 'order_items'
422+
}
423+
```
424+
250425

251426
### Meta
252427

@@ -260,10 +435,17 @@ added to the `meta` object within the same `data` as the serializer.
260435
To add metadata to the top level `meta` object add:
261436

262437
``` python
263-
def get_root_meta(self, obj):
264-
return {
265-
'size': len(obj)
266-
}
438+
def get_root_meta(self, resource, many):
439+
if many:
440+
# Dealing with a list request
441+
return {
442+
'size': len(resource)
443+
}
444+
else:
445+
# Dealing with a detail request
446+
return {
447+
'foo': 'bar'
448+
}
267449
```
268450
to the serializer. It must return a dict and will be merged with the existing top level `meta`.
269451

‎example/factories/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# -*- encoding: utf-8 -*-
2-
from __future__ import unicode_literals
32

43
import factory
54
from faker import Factory as FakerFactory
@@ -22,6 +21,7 @@ class Meta:
2221
name = factory.LazyAttribute(lambda x: faker.name())
2322
email = factory.LazyAttribute(lambda x: faker.email())
2423

24+
bio = factory.RelatedFactory('example.factories.AuthorBioFactory', 'author')
2525

2626
class AuthorBioFactory(factory.django.DjangoModelFactory):
2727
class Meta:

0 commit comments

Comments
(0)

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