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 55e8def

Browse files
santiavenda2sliverc
authored andcommitted
Avoid exception in AutoPrefetchMixin when including a reverse one to one relation (#536)
1 parent 11e0edd commit 55e8def

File tree

9 files changed

+104
-8
lines changed

9 files changed

+104
-8
lines changed

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ any parts of the framework not mentioned in the documentation should generally b
2929
* Do not skip empty one-to-one relationships
3030
* Allow `HyperlinkRelatedField` to be used with [related urls](https://django-rest-framework-json-api.readthedocs.io/en/stable/usage.html?highlight=related%20links#related-urls)
3131
* Fixed hardcoded year 2018 in tests ([#539](https://github.com/django-json-api/django-rest-framework-json-api/issues/539))
32+
* Avoid exception in `AutoPrefetchMixin` when including a reverse one to one relation ([#537](https://github.com/django-json-api/django-rest-framework-json-api/issues/537))
3233

3334
## [2.6.0] - 2018年09月20日
3435

‎example/factories.py‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
Entry,
1515
ProjectType,
1616
ResearchProject,
17-
TaggedItem
18-
)
17+
TaggedItem,
18+
AuthorBioMetadata)
1919

2020
faker = FakerFactory.create()
2121
faker.seed(983843)
@@ -53,6 +53,16 @@ class Meta:
5353
author = factory.SubFactory(AuthorFactory)
5454
body = factory.LazyAttribute(lambda x: faker.text())
5555

56+
metadata = factory.RelatedFactory('example.factories.AuthorBioMetadataFactory', 'bio')
57+
58+
59+
class AuthorBioMetadataFactory(factory.django.DjangoModelFactory):
60+
class Meta:
61+
model = AuthorBioMetadata
62+
63+
bio = factory.SubFactory(AuthorBioFactory)
64+
body = factory.LazyAttribute(lambda x: faker.text())
65+
5666

5767
class EntryFactory(factory.django.DjangoModelFactory):
5868
class Meta:
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Generated by Django 2.1.4 on 2018年12月28日 07:52
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('example', '0005_auto_20180922_1508'),
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name='AuthorBioMetadata',
16+
fields=[
17+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18+
('created_at', models.DateTimeField(auto_now_add=True)),
19+
('modified_at', models.DateTimeField(auto_now=True)),
20+
('body', models.TextField()),
21+
('bio', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='metadata', to='example.AuthorBio')),
22+
],
23+
options={
24+
'ordering': ('id',),
25+
},
26+
),
27+
migrations.AlterField(
28+
model_name='comment',
29+
name='author',
30+
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='example.Author'),
31+
),
32+
]

‎example/models.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,21 @@ class Meta:
8181
ordering = ('id',)
8282

8383

84+
@python_2_unicode_compatible
85+
class AuthorBioMetadata(BaseModel):
86+
"""
87+
Just a class to have a relation with author bio
88+
"""
89+
bio = models.OneToOneField(AuthorBio, related_name='metadata', on_delete=models.CASCADE)
90+
body = models.TextField()
91+
92+
def __str__(self):
93+
return self.bio.author.name
94+
95+
class Meta:
96+
ordering = ('id',)
97+
98+
8499
@python_2_unicode_compatible
85100
class Entry(BaseModel):
86101
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)

‎example/serializers.py‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
Project,
1717
ProjectType,
1818
ResearchProject,
19-
TaggedItem
20-
)
19+
TaggedItem,
20+
AuthorBioMetadata)
2121

2222

2323
class TaggedItemSerializer(serializers.ModelSerializer):
@@ -197,7 +197,17 @@ class Meta:
197197
class AuthorBioSerializer(serializers.ModelSerializer):
198198
class Meta:
199199
model = AuthorBio
200-
fields = ('author', 'body')
200+
fields = ('author', 'body', 'metadata')
201+
202+
included_serializers = {
203+
'metadata': 'example.serializers.AuthorBioMetadataSerializer',
204+
}
205+
206+
207+
class AuthorBioMetadataSerializer(serializers.ModelSerializer):
208+
class Meta:
209+
model = AuthorBioMetadata
210+
fields = ('body',)
201211

202212

203213
class AuthorSerializer(serializers.ModelSerializer):

‎example/tests/conftest.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
ArtProjectFactory,
77
AuthorBioFactory,
88
AuthorFactory,
9+
AuthorBioMetadataFactory,
910
AuthorTypeFactory,
1011
BlogFactory,
1112
CommentFactory,
@@ -18,6 +19,7 @@
1819
register(BlogFactory)
1920
register(AuthorFactory)
2021
register(AuthorBioFactory)
22+
register(AuthorBioMetadataFactory)
2123
register(AuthorTypeFactory)
2224
register(EntryFactory)
2325
register(CommentFactory)

‎example/tests/integration/test_includes.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,25 @@ def test_included_data_on_list(multiple_entries, client):
2020
assert comment_count == expected_comment_count, 'List comment count is incorrect'
2121

2222

23+
def test_included_data_on_list_with_one_to_one_relations(multiple_entries, client):
24+
response = client.get(reverse("entry-list"),
25+
data={'include': 'authors.bio.metadata', 'page[size]': 5})
26+
included = response.json().get('included')
27+
28+
assert len(response.json()['data']) == len(multiple_entries), (
29+
'Incorrect entry count'
30+
)
31+
expected_include_types = [
32+
'authorBioMetadata', 'authorBioMetadata',
33+
'authorBios', 'authorBios',
34+
'authors', 'authors'
35+
]
36+
include_types = [x.get('type') for x in included]
37+
assert include_types == expected_include_types, (
38+
'List included types are incorrect'
39+
)
40+
41+
2342
def test_default_included_data_on_detail(single_entry, client):
2443
return test_included_data_on_detail(single_entry=single_entry, client=client, query='')
2544

‎example/tests/test_views.py‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
2-
32
from datetime import datetime
3+
44
from django.test import RequestFactory
55
from django.utils import timezone
66
from rest_framework.exceptions import NotFound
@@ -337,7 +337,10 @@ def test_retrieve_related_single_reverse_lookup(self):
337337
'data': {
338338
'type': 'authorBios', 'id': str(self.author.bio.id),
339339
'relationships': {
340-
'author': {'data': {'type': 'authors', 'id': str(self.author.id)}}},
340+
'author': {'data': {'type': 'authors', 'id': str(self.author.id)}},
341+
'metadata': {'data': {'id': str(self.author.bio.metadata.id),
342+
'type': 'authorBioMetadata'}}
343+
},
341344
'attributes': {
342345
'body': str(self.author.bio.body)
343346
},

‎rest_framework_json_api/views.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,11 @@ def get_queryset(self, *args, **kwargs):
9292
if level == levels[-1]:
9393
included_model = field
9494
else:
95-
model_field = field.field
95+
96+
if issubclass(field_class, ReverseOneToOneDescriptor):
97+
model_field = field.related.field
98+
else:
99+
model_field = field.field
96100

97101
if is_forward_relation:
98102
level_model = model_field.related_model

0 commit comments

Comments
(0)

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