Skip to content

Commit 3471569

Browse files
committed
Merge branch 'develop'
2 parents b9ccd9d + 97e1a6c commit 3471569

27 files changed

+545
-3278
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ pip-delete-this-directory.txt
2828
# Pycharm project files
2929
.idea/
3030

31+
# PyTest cache
32+
.cache/
33+
3134
# Tox
3235
.tox/
3336

.travis.yml

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,38 @@
1+
---
12
language: python
2-
python: 3.5
33
sudo: false
4-
install: pip install tox
5-
script: tox
4+
cache: pip
5+
matrix:
6+
exclude:
7+
- python: "3.3"
8+
env: DJANGO=">=1.9,<1.10" DRF=">=3.3,<3.4"
9+
- python: "3.3"
10+
env: DJANGO=">=1.9,<1.10" DRF=">=3.4,<3.5"
11+
- python: "3.3"
12+
env: DJANGO=">=1.10,<1.11" DRF=">=3.4,<3.5"
13+
python:
14+
- "2.7"
15+
- "3.3"
16+
- "3.4"
17+
- "3.5"
618
env:
7-
- TOXENV=py27-django17-drf31
8-
- TOXENV=py27-django17-drf32
9-
- TOXENV=py33-django17-drf31
10-
- TOXENV=py33-django17-drf32
11-
- TOXENV=py34-django17-drf31
12-
- TOXENV=py34-django17-drf32
13-
- TOXENV=py27-django18-drf31
14-
- TOXENV=py27-django18-drf32
15-
- TOXENV=py27-django18-drf33
16-
- TOXENV=py33-django18-drf31
17-
- TOXENV=py33-django18-drf32
18-
- TOXENV=py33-django18-drf33
19-
- TOXENV=py34-django18-drf31
20-
- TOXENV=py34-django18-drf32
21-
- TOXENV=py34-django18-drf33
22-
- TOXENV=py27-django19-drf31
23-
- TOXENV=py27-django19-drf32
24-
- TOXENV=py27-django19-drf33
25-
- TOXENV=py34-django19-drf31
26-
- TOXENV=py34-django19-drf32
27-
- TOXENV=py34-django19-drf33
28-
- TOXENV=py35-django19-drf31
29-
- TOXENV=py35-django19-drf32
30-
- TOXENV=py35-django19-drf33
19+
- DJANGO=">=1.8,<1.9" DRF=">=3.1,<3.2"
20+
- DJANGO=">=1.8,<1.9" DRF=">=3.2,<3.3"
21+
- DJANGO=">=1.8,<1.9" DRF=">=3.3,<3.4"
22+
- DJANGO=">=1.8,<1.9" DRF=">=3.4,<3.5"
23+
24+
- DJANGO=">=1.9,<1.10" DRF=">=3.3,<3.4"
25+
- DJANGO=">=1.9,<1.10" DRF=">=3.4,<3.5"
26+
27+
- DJANGO=">=1.10,<1.11" DRF=">=3.4,<3.5"
28+
before_install:
29+
# Force an upgrade of py to avoid VersionConflict
30+
- pip install --upgrade py
31+
- pip install codecov
32+
install:
33+
- pip install Django${DJANGO} djangorestframework${DRF}
34+
- python setup.py install
35+
script:
36+
- coverage run setup.py -v test
37+
after_success:
38+
- codecov

CHANGELOG.md

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

2+
v2.1.0
3+
4+
* Parse `meta` in JSONParser
5+
* Added code coverage reporting and updated Django versions tested against
6+
* Fixed Django 1.10 compatibility
7+
* Added support for regular non-ModelSerializers
8+
* Added performance enhancements to reduce the number of queries in related payloads
9+
* Fixed bug where related `SerializerMethodRelatedField` fields were not included even if in `include`
10+
* Convert `include` field names back to snake_case
11+
* Documented built in `url` field for generating a `self` link in the `links` key
12+
* Fixed bug that prevented `fields = ()` in a serializer from being valid
13+
* Fixed stale data returned in PATCH to-one relation
14+
* Raise a `ParseError` if an `id` is not included in a PATCH request
15+
16+
v2.0.1
17+
18+
* Fixed naming error that caused ModelSerializer relationships to fail
19+
220
v2.0.0
321

422
* Fixed bug where write_only fields still had their keys rendered

docs/api.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,14 @@ 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+
51+
## rest_framework_json_api.parsers.JSONParser
52+
53+
Similar to `JSONRenderer`, the `JSONParser` you may override the following methods if you need
54+
highly custom parsing control.
55+
56+
#### parse_metadata
57+
58+
`parse_metadata(result)`
59+
60+
Returns a dictionary which will be merged into parsed data of the request. By default, it reads the `meta` content in the request body and returns it in a dictionary with a `_meta` top level key.

docs/usage.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ class LineItemViewSet(viewsets.ModelViewSet):
375375

376376
### RelationshipView
377377
`rest_framework_json_api.views.RelationshipView` is used to build
378-
relationship views (see the
378+
relationship views (see the
379379
[JSON API spec](http://jsonapi.org/format/#fetching-relationships)).
380380
The `self` link on a relationship object should point to the corresponding
381381
relationship view.
@@ -449,9 +449,16 @@ def get_root_meta(self, resource, many):
449449
```
450450
to the serializer. It must return a dict and will be merged with the existing top level `meta`.
451451

452+
To access metadata in incoming requests, the `JSONParser` will add the metadata under a top level `_meta` key in the parsed data dictionary. For instance, to access meta data from a `serializer` object, you may use `serializer.initial_data.get("_meta")`. To customize the `_meta` key, see [here](api.md).
453+
454+
### Links
455+
456+
Adding `url` to `fields` on a serializer will add a `self` link to the `links` key.
457+
458+
Related links will be created automatically when using the Relationship View.
459+
452460
<!--
453461
### Relationships
454-
### Links
455462
### Included
456463
### Errors
457464
-->

drf_example

4 KB
Binary file not shown.

example/migrations/0001_initial.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.9.5 on 2016-05-02 08:26
3+
from __future__ import unicode_literals
4+
5+
from django.db import migrations, models
6+
import django.db.models.deletion
7+
8+
9+
class Migration(migrations.Migration):
10+
11+
initial = True
12+
13+
dependencies = [
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name='Author',
19+
fields=[
20+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21+
('created_at', models.DateTimeField(auto_now_add=True)),
22+
('modified_at', models.DateTimeField(auto_now=True)),
23+
('name', models.CharField(max_length=50)),
24+
('email', models.EmailField(max_length=254)),
25+
],
26+
options={
27+
'abstract': False,
28+
},
29+
),
30+
migrations.CreateModel(
31+
name='AuthorBio',
32+
fields=[
33+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
34+
('created_at', models.DateTimeField(auto_now_add=True)),
35+
('modified_at', models.DateTimeField(auto_now=True)),
36+
('body', models.TextField()),
37+
('author', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='bio', to='example.Author')),
38+
],
39+
options={
40+
'abstract': False,
41+
},
42+
),
43+
migrations.CreateModel(
44+
name='Blog',
45+
fields=[
46+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
47+
('created_at', models.DateTimeField(auto_now_add=True)),
48+
('modified_at', models.DateTimeField(auto_now=True)),
49+
('name', models.CharField(max_length=100)),
50+
('tagline', models.TextField()),
51+
],
52+
options={
53+
'abstract': False,
54+
},
55+
),
56+
migrations.CreateModel(
57+
name='Comment',
58+
fields=[
59+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
60+
('created_at', models.DateTimeField(auto_now_add=True)),
61+
('modified_at', models.DateTimeField(auto_now=True)),
62+
('body', models.TextField()),
63+
('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='example.Author')),
64+
],
65+
options={
66+
'abstract': False,
67+
},
68+
),
69+
migrations.CreateModel(
70+
name='Entry',
71+
fields=[
72+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
73+
('created_at', models.DateTimeField(auto_now_add=True)),
74+
('modified_at', models.DateTimeField(auto_now=True)),
75+
('headline', models.CharField(max_length=255)),
76+
('body_text', models.TextField(null=True)),
77+
('pub_date', models.DateField(null=True)),
78+
('mod_date', models.DateField(null=True)),
79+
('n_comments', models.IntegerField(default=0)),
80+
('n_pingbacks', models.IntegerField(default=0)),
81+
('rating', models.IntegerField(default=0)),
82+
('authors', models.ManyToManyField(to='example.Author')),
83+
('blog', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='example.Blog')),
84+
],
85+
options={
86+
'abstract': False,
87+
},
88+
),
89+
migrations.AddField(
90+
model_name='comment',
91+
name='entry',
92+
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='example.Entry'),
93+
),
94+
]

example/migrations/__init__.py

Whitespace-only changes.

example/serializers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def get_root_meta(self, resource, many):
1717

1818
class Meta:
1919
model = Blog
20-
fields = ('name', )
20+
fields = ('name', 'url',)
2121
meta_fields = ('copyright',)
2222

2323

@@ -35,6 +35,7 @@ def __init__(self, *args, **kwargs):
3535
'authors': 'example.serializers.AuthorSerializer',
3636
'comments': 'example.serializers.CommentSerializer',
3737
'featured': 'example.serializers.EntrySerializer',
38+
'suggested': 'example.serializers.EntrySerializer',
3839
}
3940

4041
body_format = serializers.SerializerMethodField()

example/settings/dev.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,29 @@
2626
'example',
2727
]
2828

29+
TEMPLATES = [
30+
{
31+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
32+
'DIRS': [
33+
# insert your TEMPLATE_DIRS here
34+
],
35+
'APP_DIRS': True,
36+
'OPTIONS': {
37+
'context_processors': [
38+
# Insert your TEMPLATE_CONTEXT_PROCESSORS here or use this
39+
# list if you haven't customized them:
40+
'django.contrib.auth.context_processors.auth',
41+
'django.template.context_processors.debug',
42+
'django.template.context_processors.i18n',
43+
'django.template.context_processors.media',
44+
'django.template.context_processors.static',
45+
'django.template.context_processors.tz',
46+
'django.contrib.messages.context_processors.messages',
47+
],
48+
},
49+
},
50+
]
51+
2952
STATIC_URL = '/static/'
3053

3154
ROOT_URLCONF = 'example.urls'

0 commit comments

Comments
 (0)