from django import forms from django.utils.translation import ugettext as _ from drill.forms import GameSettings, Question from drill.models import Word, WordTranslation from gamesettings.yamltools import yget from django.db.models import Q, Count YAML_SAMPLE = """ Leksa: questions: - question: model: 'Word' attribute: 'lemma' answer: model: 'WordTranslation' attribute: 'definition' taxonomy: - "languagepairs": model: 'Word' attribute: 'language' - "semtypes": model: 'Word' attribute: 'semtype__semtype' languagepairs: - ["sma", "nob"] semtypes: - ['HUMAN', 'Human'] """ class YAMLSettings(object): def get(self, path): return yget(self.yamldict, path) def toGetTextTuples(self, opts): return [(a, _(b)) for a, b in opts] def taxonomies(self): taxes = self.yamldict['taxonomy'] choices = {} taxonomies = {} for tax, opts in taxes.items(): proc_opts = self.toGetTextTuples(opts['choices']) self.__setattr__(tax, proc_opts) taxonomies[tax] = proc_opts self.choices = choices self.taxonomies = taxonomies def questionAnswer(self): QAs = self.yamldict['questions'] QA = [] for item in QAs: pass def __init__(self, fname, gamename): import yaml with open(fname, 'r') as F: data = F.read() config_data = yaml.load(data) self.yamldict = config_data[gamename] or False self.taxonomies() # parse YAML # question sets # taxonomies (create objects to set forms) import settings as S yfile = S.GAME_SETTINGS class LeksaSettings(GameSettings): """ Leksa settings form. TODO: Method to set session data according to settings. """ select = {'widget': forms.Select} def __init__(self, *args, **kwargs): gametype = type(self).__name__ # Leksa self.yaml = YAMLSettings(yfile, gametype) if 'preset_fields' in kwargs: preset_fields = kwargs['preset_fields'] else: preset_fields = {} for tax, opts in self.yaml.taxonomies.items(): t = self.yaml.get('taxonomy/%s' % tax) if 'choices' in t: fieldtype = forms.ChoiceField preset_fields[tax] = fieldtype(initial=opts[0][0], choices=opts, **self.select) # self.__setattr__(tax, field) kwargs['preset_fields'] = preset_fields super(LeksaSettings, self).__init__(*args, **kwargs) def makeQuery(self): if self.is_valid(): options = self.cleaned_data else: options = self.initial_data for tax, opts in self.yaml.taxonomies.items(): t = self.yaml.get('taxonomy/%s' % tax) qkwargs = {} if tax in options: qkwargs[t['attr']] = options[tax] QUERY = Q(**qkwargs) self.query = QUERY return True def getInitialData(self): """ Get initial data to populate formsets. """ if self.is_valid(): options = self.cleaned_data else: options = self.initial_data answer_language = options['transtype'][-3::] question_language = options['transtype'][0:3] initialwords = Word.objects.filter(language=question_language, wordtranslation__language=answer_language) initialwords = initialwords.filter(self.query)\ .order_by('?')[0:self.question_count] inits = [] for word in initialwords: xls = word.wordtranslation_set.filter(language=answer_language) translations = [x.definition for x in xls if x.definition.strip()] app = { 'id': word.id, 'lemma': word.lemma, 'translations': translations} inits.append(app) return inits class Leksa(LeksaSettings): pass class LeksaPlace(LeksaSettings): pass class LeksaQuestion(Question): """ This is the Leksa question class. It produces only one question, and has methods to validate whether this question is correct or not. Incorrect answers throw validation errors and provide a reason as the error message. This question should be used in a Formset. Most of the functionality is in the Question parent class, except for check_anwer. """ def check_answer(self): """ Check answers. TODO: Turn this into a validator. """ answers = self.cleaned_data.get("answers") user_answer = self.cleaned_data.get("userans") if answers: if user_answer not in answers: self._errors["userans"] = self.Errors.try_again self.correct = False else: self.correct = True else: self._errors = self.Errors.empty_answers if not user_answer: self._errors["userans"] = self.Errors.blank_user_answer return