diff --git a/minerva/questions.py b/minerva/questions.py index dc74615..ed10e46 100644 --- a/minerva/questions.py +++ b/minerva/questions.py @@ -1,7 +1,12 @@ +import bisect import random +from django.conf import settings +from django.core.cache import cache + from minerva.models import Word + QUESTION_SCENARIOS = ( # Question, answer ('word', 'meaning'), @@ -22,10 +27,7 @@ def create_question(user, language, level, num_choices=4): # TODO: Right now, this is very simple (doesn't take into account the # user's performance at all). Eventually, it will be a graded selection # based on what the user finds difficult, etc. - - # FIXME: Cache this, for each language. - pks = Word.objects.filter(lang_code__code=language, level=level). \ - values_list("pk", flat=True) + pks = word_keys(language, level) sampled_words = list(Word.objects.filter(pk__in=random.sample(pks, num_choices))) question_attribute, answer_attribute = random.choice(QUESTION_SCENARIOS) @@ -35,3 +37,20 @@ def create_question(user, language, level, num_choices=4): for item in sampled_words] return question_data, answers +def word_keys(code, level): + """ + Retrieves all the pk values for words for the language "code" and "level". + This interacts sensibly with the cache system to avoid unnecessary database + round trips. + + Returns a list of pk values. + """ + full_list = cache.get(code) + if not full_list: + full_list = tuple(Word.objects.filter(lang_code__code=code). \ + values_list("level", "pk").order_by("level")) + cache.set(code, full_list, settings.LANG_CACHE_TIMEOUT) + start = bisect.bisect_right(full_list, (level - 1, 0)) + end = bisect.bisect_left(full_list, (level + 1, 0)) + return [item[1] for item in full_list[start : end]] + diff --git a/settings.py b/settings.py index 95d427d..2a1df62 100644 --- a/settings.py +++ b/settings.py @@ -101,5 +101,8 @@ "INTERCEPT_REDIRECTS": False, } +# Cache period, in seconds, for language data (which hardly ever changes) +LANG_CACHE_TIMEOUT = 10800 + utils.load_external_settings("host_settings", globals())