refactor: centralize user preference caching in the model layer#74
Merged
Conversation
fc4edbc to
27b8cda
Compare
0b35779 to
d84da9d
Compare
2add834 to
8619abf
Compare
Refactored caching logic by moving cache management from the API layer to the `UserPreference` model. This change ensures that `get_all_preferences` handles its own caching consistently, preventing stale data issues previously caused by the `@request_cached` decorator and manual API-level caching. Changes: - Moved cache helpers to `user_api/helpers.py`. - Updated `UserPreference.get_all_preferences` to use the new caching logic. - Cleaned up `user_api/preferences/api.py` to remove redundant cache checks, delegating to the model instead. - Ensured cache invalidation is triggered correctly on create/update/delete operations.
johanseto
approved these changes
May 14, 2026
johanseto
left a comment
Collaborator
There was a problem hiding this comment.
Lets move it to upstream. This reduce number of queries to the db with the cache management
|
|
||
|
|
||
| def user_preferences_cache_key(user_id): | ||
| return f"{USER_PREFERENCE_CACHE_KEY_PREFIX}.{user_id}" |
Added comprehensive Google-style docstrings to cache key generation, retrieval, storage, and invalidation functions. Improved code maintainability and clarified expected parameter types.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request: Refactor UserPreference Caching and Reduce Query Counts
Summary
This PR refactors the caching mechanism for user preferences. It migrates the caching responsibility from the API layer (
api.py) and the request-scoped memory (@request_cachedinmodels.py) to the Model layer itself using Django's standard caching framework via helper functions. This centralization improves cache utilization across the platform and results in a verifiable reduction in database queries.To support this architectural change without breaking query-count tests in environments that default to
DummyCache(like the LMS test suite),LocMemCacheoverrides were added to the affected test cases.Key Changes
1. Architectural Refactoring (Caching)
api.pyand moved them toopenedx/core/djangoapps/user_api/helpers.py.@request_cached()decorator fromUserPreference.get_all_preferences()inmodels.py. The caching logic is now explicitly handled inside this method using the new helper functions.openedx/core/djangoapps/user_api/preferences/api.py. Methods likehas_user_preference,get_user_preference, andget_user_preferencesnow directly delegate toUserPreference.get_all_preferences(), relying on the model to handle the cache Hit/Miss logic.2. Query Count Optimizations & Test Adjustments
content_tagging/rest_api/v1/tests/test_views.py(e.g.,test_list_taxonomy_query_count,test_object_tags_query_count,test_taxonomy_tags_query_count) due to the improved global caching of preferences.lang_pref/tests/test_middleware.py(test_preference_update_noop) from 1 to 0 and 3 to 2.@override_settings(CACHES={'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}})toIndexQueryTestCase(LMS) andtest_preference_update_noop(Middleware). Because the code no longer relies on therequest_cachedthread-local memory, these tests require a functional cache backend (LocMemCacheinstead of the test environment's defaultDummyCache) to correctly assert the optimized query counts.Impact