Skip to content
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

Do not lazy load forward relations #461

Merged
merged 4 commits into from
Sep 4, 2018

Conversation

timcbaoth
Copy link
Contributor

@timcbaoth timcbaoth commented Aug 21, 2018

If the forward relations are included, the renderer will break, so this optimization only works if it is not included.

Description of the Change

Fixes a copy paste error, which resulted in an optimization not being applied.

Checklist

  • PR only contains one change (considered splitting up PR)
  • unit-test added
  • documentation updated
  • changelog entry added to CHANGELOG.md
  • author name in AUTHORS

@codecov-io
Copy link

codecov-io commented Aug 21, 2018

Codecov Report

Merging #461 into master will increase coverage by 0.29%.
The diff coverage is 98.11%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #461      +/-   ##
==========================================
+ Coverage   93.44%   93.73%   +0.29%     
==========================================
  Files          56       56              
  Lines        3217     3255      +38     
==========================================
+ Hits         3006     3051      +45     
+ Misses        211      204       -7
Impacted Files Coverage Δ
example/tests/test_serializers.py 100% <100%> (ø) ⬆️
rest_framework_json_api/serializers.py 85.88% <94.11%> (+4.63%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a320536...91bb86d. Read the comment docs.

@sliverc
Copy link
Member

sliverc commented Aug 21, 2018

Could you elaborate what you mean with the rendererer will break? I think best would be to reproduce this in a test case then I think things will be clearer and we make sure this error won't happen again in the future.

@timcbaoth
Copy link
Contributor Author

The quoted part is only an explanation for why I added the check
is_included = field.source in get_included_resources(request)
The meat of the fix was changing
and hasattr(field, field.source + "_id")
to
and hasattr(instance, field.source + "_id")
in the if statement, which was probably a typo in the first place.

I will try to submit a test case to cover these changes.

@timcbaoth timcbaoth force-pushed the include-forward-relation branch from a7c0766 to bba4f6e Compare August 28, 2018 14:38
@timcbaoth
Copy link
Contributor Author

A test case was added.

Copy link
Member

@sliverc sliverc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation looks good. Just a few comments on the testing front.
Thanks for working on this.

@@ -30,6 +32,32 @@ def setUp(self):
Author.objects.create(name=name, email='{}@example.org'.format(name))
)

def test_forward_relationship_not_loaded_when_not_included(self):
MockRequest = namedtuple('Request', ['query_params'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe better to use from rest_framework.test import APIRequestFactory. There is an example in unit/test_pagination.py how to use it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

fields = '__all__'

def to_representation(self, instance):
raise Exception('to_representation of BlogSerializer was called')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the disadvantage of this way of testing is that this code will actually never be covered. A bit odd when test code is not covered and the long term goal of DJA would be to have 100% coverage.

So I would prefer if the already existing serializers in example/serializers.py are used for this. to_representation would need to be mocked and assert_not_called could be used to check that to_representation has not been called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't think about it in this way, that you also want full coverage on test code itself. Interesting.

Anyway it is nicer to have a proper assert, so I changed it according to your suggestion.

}

serializer = EntrySerializer(context={'request': request_without_includes})
serializer.to_representation(self.entry)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would also be good to assert the result.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I added another test to validate the result.

return ret

def _get_field_representation(self, field, instance):
request = self.context.get('request', None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None is the default return value when using get. So seems to be a bit cleaner to use self.context.get('request').

👍 to extract this logic into its own method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it. Good suggestion!

@timcbaoth timcbaoth force-pushed the include-forward-relation branch from 4239178 to 64f8ae3 Compare August 29, 2018 13:46
Copy link
Member

@sliverc sliverc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

One small comment + rebase to master + add yourself to AUTHROS + changelog entry and I think this is ready for merging.

result.pop('created_at')
result.pop('modified_at')

expected = OrderedDict(
Copy link
Member

@sliverc sliverc Aug 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ordering is not relevant in an assertion so I think the code would be more readable using normal dict.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I will also change it to assertDictEqual.

@timcbaoth timcbaoth force-pushed the include-forward-relation branch from 64f8ae3 to 7186b0c Compare August 31, 2018 08:39
If the forward relations are included, the renderer will break, so this optimization only works if it is not included.

fixup! Do not lazy load forward relations

fixup! Do not lazy load forward relations

fixup! Do not lazy load forward relations

fixup! Do not lazy load forward relations

fixup! Do not lazy load forward relations

Include test case

Small refactoring

Make compatible with Python 2.X

fixup! Make compatible with Python 2.X

Fix travis

Use isort

Implement suggested changes

Make import backward compatible

Make travis happy
@timcbaoth timcbaoth force-pushed the include-forward-relation branch from 7186b0c to 91bb86d Compare August 31, 2018 08:48
@sliverc sliverc merged commit 22c4587 into django-json-api:master Sep 4, 2018
@n2ygk n2ygk added this to the 2.6.0 milestone Sep 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants