-
Notifications
You must be signed in to change notification settings - Fork 301
Issue #337 #366
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
Issue #337 #366
Changes from all commits
aa962c1
da0c94c
1d84c80
9e284f4
b4999e4
cacca2e
5a7d73a
e96fe6c
8fdbc0a
46c3809
3c24093
151bdb9
844e88e
07f67a3
f924ac8
97b6dd3
f0bda69
63020b4
a7130b9
7343def
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,4 +40,7 @@ pip-delete-this-directory.txt | |
# VirtualEnv | ||
.venv/ | ||
|
||
# Developers | ||
*.sw* | ||
manage.py | ||
.DS_Store |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
from django.utils import timezone | ||
from rest_framework.test import APITestCase | ||
|
||
from example.factories import CommentFactory | ||
from example.models import Author, Blog, Comment, Entry | ||
|
||
|
||
class PerformanceTestCase(APITestCase): | ||
def setUp(self): | ||
self.author = Author.objects.create(name='Super powerful superhero', email='[email protected]') | ||
self.blog = Blog.objects.create(name='Some Blog', tagline="It's a blog") | ||
self.other_blog = Blog.objects.create(name='Other blog', tagline="It's another blog") | ||
self.first_entry = Entry.objects.create( | ||
blog=self.blog, | ||
headline='headline one', | ||
body_text='body_text two', | ||
pub_date=timezone.now(), | ||
mod_date=timezone.now(), | ||
n_comments=0, | ||
n_pingbacks=0, | ||
rating=3 | ||
) | ||
self.second_entry = Entry.objects.create( | ||
blog=self.blog, | ||
headline='headline two', | ||
body_text='body_text one', | ||
pub_date=timezone.now(), | ||
mod_date=timezone.now(), | ||
n_comments=0, | ||
n_pingbacks=0, | ||
rating=1 | ||
) | ||
self.comment = Comment.objects.create(entry=self.first_entry) | ||
CommentFactory.create_batch(50) | ||
|
||
def test_query_count_no_includes(self): | ||
""" We expect a simple list view to issue only two queries. | ||
|
||
1. The number of results in the set (e.g. a COUNT query), | ||
only necessary because we're using PageNumberPagination | ||
2. The SELECT query for the set | ||
""" | ||
with self.assertNumQueries(2): | ||
response = self.client.get('/comments?page_size=25') | ||
self.assertEqual(len(response.data['results']), 25) | ||
|
||
def test_query_count_include_author(self): | ||
""" We expect a list view with an include have three queries: | ||
|
||
1. Primary resource COUNT query | ||
2. Primary resource SELECT | ||
3. Authors prefetched | ||
3. Entries prefetched | ||
""" | ||
with self.assertNumQueries(4): | ||
response = self.client.get('/comments?include=author&page_size=25') | ||
self.assertEqual(len(response.data['results']), 25) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from rest_framework.renderers import BrowsableAPIRenderer | ||
|
||
|
||
class BrowsableAPIRendererWithoutForms(BrowsableAPIRenderer): | ||
"""Renders the browsable api, but excludes the forms.""" | ||
|
||
def get_context(self, *args, **kwargs): | ||
ctx = super().get_context(*args, **kwargs) | ||
ctx['display_edit_forms'] = False | ||
return ctx | ||
|
||
def show_form_for_method(self, view, method, request, obj): | ||
"""We never want to do this! So just return False.""" | ||
return False | ||
|
||
def get_rendered_html_form(self, data, view, method, request): | ||
"""Why render _any_ forms at all. This method should return | ||
rendered HTML, so let's simply return an empty string. | ||
""" | ||
return "" |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,8 +74,13 @@ class AuthorViewSet(ModelViewSet): | |
|
||
|
||
class CommentViewSet(ModelViewSet): | ||
queryset = Comment.objects.all() | ||
queryset = Comment.objects.select_related('author', 'entry') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still have an issue with the way relations are extracted first level... I had to prefetch things that I shouldn't have to only to make tests pass... Feels like the queryset might be over reaching to overcome an issue with drf_jsonapi. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After further investigation, the problem does not occur inside extract_relationships - Still looking There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jsenecal the problem is in two places, setting use_pk_only_optimization to False, and extract_attributes. You have to whack them both, which made it so hard to find the source of the explosion. I think you should probably remove the select_related in this because the tests should fail until we fix that other issue? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for this - I merged already but will update my branch to reflect this conversation |
||
serializer_class = CommentSerializer | ||
prefetch_for_includes = { | ||
'__all__': [], | ||
'author': ['author', 'author__bio', 'author__entries'], | ||
'entry': ['author', 'author__bio', 'author__entries'] | ||
} | ||
|
||
|
||
class CompanyViewset(ModelViewSet): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,6 @@ recommonmark | |
Sphinx | ||
sphinx_rtd_theme | ||
tox | ||
mock | ||
django-debug-toolbar | ||
packaging==16.8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this ignoring
manage.py
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aidanlister must have a custom one (introduced by da0c94c).
We're not using it to start the app anyways (
$ django-admin.py runserver --settings=example.settings
)