diff --git a/cms/startup.py b/cms/startup.py index 55244c9045..42c7eb1070 100644 --- a/cms/startup.py +++ b/cms/startup.py @@ -9,7 +9,7 @@ settings.INSTALLED_APPS # pylint: disable=pointless-statement from openedx.core.lib.django_startup import autostartup import django -from monkey_patch import third_party_auth +from monkey_patch import third_party_auth, django_db_models_options import xmodule.x_module import cms.lib.xblock.runtime @@ -22,6 +22,7 @@ def run(): Executed during django startup """ third_party_auth.patch() + django_db_models_options.patch() # Comprehensive theming needs to be set up before django startup, # because modifying django template paths after startup has no effect. diff --git a/common/djangoapps/monkey_patch/django_db_models_options.py b/common/djangoapps/monkey_patch/django_db_models_options.py new file mode 100644 index 0000000000..d67373b3f9 --- /dev/null +++ b/common/djangoapps/monkey_patch/django_db_models_options.py @@ -0,0 +1,39 @@ +""" +Monkey patch implementation of the following _expire_cache performance improvement: + +https://github.com/django/django/commit/7628f87e2b1ab4b8a881f06c8973be4c368aaa3d + +Remove once we upgrade to a version of django which includes this fix natively! +NOTE: This is on django's master branch but is NOT currently part of any django 1.8 or 1.9 release. +""" + +from django.db.models.options import Options + + +def patch(): + """ + Monkey-patch the Options class. + """ + def _expire_cache(self, forward=True, reverse=True): + # pylint: disable=missing-docstring + + # This method is usually called by apps.cache_clear(), when the + # registry is finalized, or when a new field is added. + if forward: + for cache_key in self.FORWARD_PROPERTIES: + if cache_key in self.__dict__: + delattr(self, cache_key) + if reverse and not self.abstract: + for cache_key in self.REVERSE_PROPERTIES: + if cache_key in self.__dict__: + delattr(self, cache_key) + self._get_fields_cache = {} # pylint: disable=protected-access + + # Patch constants as a set instead of a list. + Options.FORWARD_PROPERTIES = {'fields', 'many_to_many', 'concrete_fields', + 'local_concrete_fields', '_forward_fields_map'} + + Options.REVERSE_PROPERTIES = {'related_objects', 'fields_map', '_relation_tree'} + + # Patch the expire_cache method to utilize constant's new set data structure. + Options._expire_cache = _expire_cache # pylint: disable=protected-access diff --git a/lms/startup.py b/lms/startup.py index ab7a20adc3..15582012ab 100644 --- a/lms/startup.py +++ b/lms/startup.py @@ -12,7 +12,7 @@ from openedx.core.lib.django_startup import autostartup import edxmako import logging import analytics -from monkey_patch import third_party_auth +from monkey_patch import third_party_auth, django_db_models_options import xmodule.x_module @@ -29,6 +29,7 @@ def run(): Executed during django startup """ third_party_auth.patch() + django_db_models_options.patch() # To override the settings before executing the autostartup() for python-social-auth if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH', False):