From d386297c7bb155793f8fd081bee13d1410428806 Mon Sep 17 00:00:00 2001 From: Ryo Chijiiwa Date: Wed, 3 Feb 2016 18:06:01 -0800 Subject: [PATCH 1/3] global serializer cache --- dynamic_rest/conf.py | 6 +++++- dynamic_rest/fields.py | 22 ++++++++++------------ install_requires.txt | 1 + tests/test_serializers.py | 6 +++--- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/dynamic_rest/conf.py b/dynamic_rest/conf.py index b5267f5c..4ad438fa 100644 --- a/dynamic_rest/conf.py +++ b/dynamic_rest/conf.py @@ -32,7 +32,11 @@ # PAGE_SIZE_QUERY_PARAM: global setting for the page size query parameter. # Can be overriden at the viewset level. - 'PAGE_SIZE_QUERY_PARAM': 'per_page' + 'PAGE_SIZE_QUERY_PARAM': 'per_page', + + # SERIALIZER_CACHE_MAX_COUNT: maximum number of serializers to cache + 'SERIALIZER_CACHE_MAX_COUNT': 1000, + } diff --git a/dynamic_rest/fields.py b/dynamic_rest/fields.py index d2361ad2..40f44391 100644 --- a/dynamic_rest/fields.py +++ b/dynamic_rest/fields.py @@ -8,12 +8,18 @@ from rest_framework import fields from rest_framework.exceptions import NotFound, ParseError from rest_framework.serializers import SerializerMethodField +import pylru from dynamic_rest.bases import DynamicSerializerBase from dynamic_rest.conf import settings from dynamic_rest.meta import is_field_remote +serializer_cache = pylru.lrucache( + settings.SERIALIZER_CACHE_MAX_COUNT +) + + class DynamicField(fields.Field): """ @@ -164,18 +170,10 @@ def root_serializer(self): def _get_cached_serializer(self, args, init_args): enabled = settings.ENABLE_SERIALIZER_CACHE - root = self.root_serializer - if not root or not self.field_name or not enabled: + if not self.parent or not self.field_name or not enabled: # Not enough info to use cache. return self.serializer_class(*args, **init_args) - if not hasattr(root, '_descendant_serializer_cache'): - # Initialize dict to use as cache on root serializer. - # Arguably this is a Serializer concern, but we'll do it - # here so it's agnostic to the exact type of the root - # serializer (i.e. it could be a DRF serializer). - root._descendant_serializer_cache = {} - key_dict = { 'parent': self.parent.__class__.__name__, 'field': self.field_name, @@ -184,14 +182,14 @@ def _get_cached_serializer(self, args, init_args): } cache_key = hash(pickle.dumps(key_dict)) - if cache_key not in root._descendant_serializer_cache: + if cache_key not in serializer_cache: szr = self.serializer_class( *args, **init_args ) - root._descendant_serializer_cache[cache_key] = szr + serializer_cache[cache_key] = szr - return root._descendant_serializer_cache[cache_key] + return serializer_cache[cache_key] def _get_request_fields_from_parent(self): """Get request fields from the parent serializer.""" diff --git a/install_requires.txt b/install_requires.txt index 94fb3bae..130a4857 100644 --- a/install_requires.txt +++ b/install_requires.txt @@ -1,2 +1,3 @@ Django>=1.7,<=1.9 djangorestframework>=3.1.0,<=3.3.0 +pylru==1.0.9 diff --git a/tests/test_serializers.py b/tests/test_serializers.py index f2d13b36..4fb00077 100644 --- a/tests/test_serializers.py +++ b/tests/test_serializers.py @@ -647,7 +647,7 @@ def test_same_serializer_class_different_fields(self): ) ) - def test_different_roots(self): + def test_different_roots_share_cache(self): serializer2 = CatSerializer( request_fields={'home': {}, 'backup_home': {}} ) @@ -655,10 +655,10 @@ def test_different_roots(self): home1 = self.serializer.fields['home'] home2 = serializer2.fields['home'] - self.assertIsNot( + self.assertIs( home1.serializer, home2.serializer, - 'Different root serializers should yield different instances.' + 'Different root serializers should share instances.' ) def test_root_serializer_cycle_busting(self): From fbabe3e7c202ea361b6fa4850c873b47db4572aa Mon Sep 17 00:00:00 2001 From: Ryo Chijiiwa Date: Wed, 3 Feb 2016 19:22:28 -0800 Subject: [PATCH 2/3] .isort.cfg --- .isort.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/.isort.cfg b/.isort.cfg index efc0bdb0..7f3c82de 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -1,2 +1,3 @@ [settings] multi_line_output=3 +known_third_party=django,pylru,rest_framework From cf930f6c20fe8b17541d8853e2d5c2b236d8cfce Mon Sep 17 00:00:00 2001 From: Ryo Chijiiwa Date: Wed, 3 Feb 2016 20:12:08 -0800 Subject: [PATCH 3/3] fix import order --- dynamic_rest/fields.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dynamic_rest/fields.py b/dynamic_rest/fields.py index 40f44391..204ae4ca 100644 --- a/dynamic_rest/fields.py +++ b/dynamic_rest/fields.py @@ -3,18 +3,17 @@ import importlib import pickle +import pylru from django.utils import six from django.utils.functional import cached_property from rest_framework import fields from rest_framework.exceptions import NotFound, ParseError from rest_framework.serializers import SerializerMethodField -import pylru from dynamic_rest.bases import DynamicSerializerBase from dynamic_rest.conf import settings from dynamic_rest.meta import is_field_remote - serializer_cache = pylru.lrucache( settings.SERIALIZER_CACHE_MAX_COUNT )