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 8218989

Browse files
Merge remote-tracking branch 'origin/master'
2 parents fd316ee + 735f485 commit 8218989

File tree

11 files changed

+106
-6
lines changed

11 files changed

+106
-6
lines changed

‎AUTHORS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Jamie Bliss <astronouth7303@gmail.com>
1414
Jason Housley <housleyjk@gmail.com>
1515
Jeppe Fihl-Pearson <jeppe@tenzer.dk>
1616
Jerel Unruh <mail@unruhdesigns.com>
17+
Jonas Metzener <jonas.metzener@adfinis.com>
1718
Jonathan Senecal <contact@jonathansenecal.com>
1819
Joseba Mendivil <git@jma.email>
1920
Kevin Partington <platinumazure@gmail.com>

‎CHANGELOG.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
Note that in line with [Django REST Framework policy](http://www.django-rest-framework.org/topics/release-notes/),
99
any parts of the framework not mentioned in the documentation should generally be considered private API, and may be subject to change.
1010

11+
## Unreleased
12+
13+
### Fixed
14+
15+
* Include `PreloadIncludesMixin` in `ReadOnlyModelViewSet` to enable the usage of [performance utilities](https://django-rest-framework-json-api.readthedocs.io/en/stable/usage.html#performance-improvements) on read only views (regression since 2.8.0)
16+
1117
## [4.2.0] - 2021年05月12日
1218

1319
### Added

‎docs/usage.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ class QuestSerializer(serializers.ModelSerializer):
940940

941941
Be aware that using included resources without any form of prefetching **WILL HURT PERFORMANCE** as it will introduce m\*(n+1) queries.
942942

943-
A viewset helper was therefore designed to automatically preload data when possible. Such is automatically available when subclassing `ModelViewSet`.
943+
A viewset helper was therefore designed to automatically preload data when possible. Such is automatically available when subclassing `ModelViewSet` or `ReadOnlyModelViewSet`.
944944

945945
It also allows to define custom `select_related` and `prefetch_related` for each requested `include` when needed in special cases:
946946

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Generated by Django 3.2.3 on 2021年05月26日 03:32
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
("example", "0008_labresults"),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name="labresults",
16+
name="author",
17+
field=models.ForeignKey(
18+
blank=True,
19+
null=True,
20+
on_delete=django.db.models.deletion.CASCADE,
21+
related_name="lab_results",
22+
to="example.author",
23+
),
24+
),
25+
]

‎example/models.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,13 @@ class LabResults(models.Model):
161161
)
162162
date = models.DateField()
163163
measurements = models.TextField()
164+
author = models.ForeignKey(
165+
Author,
166+
null=True,
167+
blank=True,
168+
on_delete=models.CASCADE,
169+
related_name="lab_results",
170+
)
164171

165172

166173
class Company(models.Model):

‎example/serializers.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,11 @@ class Meta:
356356

357357

358358
class LabResultsSerializer(serializers.ModelSerializer):
359+
included_serializers = {"author": AuthorSerializer}
360+
359361
class Meta:
360362
model = LabResults
361-
fields = ("date", "measurements")
363+
fields = ("date", "measurements", "author")
362364

363365

364366
class ProjectSerializer(serializers.PolymorphicModelSerializer):

‎example/tests/test_performance.py‎

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
from datetime import date, timedelta
2+
from random import randint
3+
14
from django.utils import timezone
25
from rest_framework.test import APITestCase
36

47
from example.factories import CommentFactory, EntryFactory
5-
from example.models import Author, Blog, Comment, Entry
8+
from example.models import Author, Blog, Comment, Entry, LabResults, ResearchProject
69

710

811
class PerformanceTestCase(APITestCase):
@@ -84,3 +87,32 @@ def test_query_prefetch_uses_included_resources(self):
8487
"/entries?fields[entries]=comments&page[size]=25"
8588
)
8689
self.assertEqual(len(response.data["results"]), 25)
90+
91+
def test_query_prefetch_read_only(self):
92+
"""We expect a read only list view with an include have five queries:
93+
94+
1. Primary resource COUNT query
95+
2. Primary resource SELECT
96+
3. Authors prefetched
97+
4. Author types prefetched
98+
5. Entries prefetched
99+
"""
100+
project = ResearchProject.objects.create(
101+
topic="Mars Mission", supervisor="Elon Musk"
102+
)
103+
104+
LabResults.objects.bulk_create(
105+
[
106+
LabResults(
107+
research_project=project,
108+
date=date.today() + timedelta(days=i),
109+
measurements=randint(0, 10000),
110+
author=self.author,
111+
)
112+
for i in range(20)
113+
]
114+
)
115+
116+
with self.assertNumQueries(5):
117+
response = self.client.get("/lab-results?include=author&page[size]=25")
118+
self.assertEqual(len(response.data["results"]), 20)

‎example/urls.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
CompanyViewset,
1818
EntryRelationshipView,
1919
EntryViewSet,
20+
LabResultViewSet,
2021
NonPaginatedEntryViewSet,
2122
ProjectTypeViewset,
2223
ProjectViewset,
@@ -32,6 +33,7 @@
3233
router.register(r"companies", CompanyViewset)
3334
router.register(r"projects", ProjectViewset)
3435
router.register(r"project-types", ProjectTypeViewset)
36+
router.register(r"lab-results", LabResultViewSet)
3537

3638
urlpatterns = [
3739
url(r"^", include(router.urls)),

‎example/urls_test.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
EntryRelationshipView,
1616
EntryViewSet,
1717
FiltersetEntryViewSet,
18+
LabResultViewSet,
1819
NoFiltersetEntryViewSet,
1920
NonPaginatedEntryViewSet,
2021
ProjectTypeViewset,
@@ -36,6 +37,7 @@
3637
router.register(r"companies", CompanyViewset)
3738
router.register(r"projects", ProjectViewset)
3839
router.register(r"project-types", ProjectTypeViewset)
40+
router.register(r"lab-results", LabResultViewSet)
3941

4042
# for the old tests
4143
router.register(r"identities", Identity)

‎example/views.py‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,22 @@
1414
)
1515
from rest_framework_json_api.pagination import JsonApiPageNumberPagination
1616
from rest_framework_json_api.utils import format_drf_errors
17-
from rest_framework_json_api.views import ModelViewSet, RelationshipView
17+
from rest_framework_json_api.views import (
18+
ModelViewSet,
19+
ReadOnlyModelViewSet,
20+
RelationshipView,
21+
)
1822

19-
from example.models import Author, Blog, Comment, Company, Entry, Project, ProjectType
23+
from example.models import (
24+
Author,
25+
Blog,
26+
Comment,
27+
Company,
28+
Entry,
29+
LabResults,
30+
Project,
31+
ProjectType,
32+
)
2033
from example.serializers import (
2134
AuthorDetailSerializer,
2235
AuthorListSerializer,
@@ -27,6 +40,7 @@
2740
CompanySerializer,
2841
EntryDRFSerializers,
2942
EntrySerializer,
43+
LabResultsSerializer,
3044
ProjectSerializer,
3145
ProjectTypeSerializer,
3246
)
@@ -266,3 +280,12 @@ class CommentRelationshipView(RelationshipView):
266280
class AuthorRelationshipView(RelationshipView):
267281
queryset = Author.objects.all()
268282
self_link_view_name = "author-relationships"
283+
284+
285+
class LabResultViewSet(ReadOnlyModelViewSet):
286+
queryset = LabResults.objects.all()
287+
serializer_class = LabResultsSerializer
288+
prefetch_for_includes = {
289+
"__all__": [],
290+
"author": ["author__bio", "author__entries"],
291+
}

0 commit comments

Comments
(0)

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