# -*- coding: utf-8 -*- from django import forms from django.forms.models import formset_factory from django.utils.translation import ugettext as _ from models import Word, Tag, Form from django.db.models import Q, Count from courses.models import UserGrade from django.http import Http404 # # # # # # # Some global choices # # # # # # from xml_settings import * # # # # # # # Settings form classes # # # # # class GameSettings(forms.Form): """ Provides some generalized methods to MorfaSettings and LeksaSettings. General idea is that the game will call one of the following: MorfaS, MorfaV, MorfaAdj, MorfaNum LeksaSettings MorfaSettings is broken up into subclasses in order to keep things easier to debug. MorfaSettings has several methods, but no form fields. Form fields are on the subforms. GameSettings.__init__() GameSettings.set_defaults() MorfaSettings MorfaS makeQuery getInitialData Returns initial data to the views, which produce a formset of 5 Question classes. Question classes are populated by the formset using data from MorfaSettings.getInitialData. """ question_count = 5 def __init__(self, *args, **kwargs): if 'preset_fields' in kwargs: preset_fields = kwargs['preset_fields'] kwargs.pop('preset_fields') else: preset_fields = False super(GameSettings, self).__init__(*args, **kwargs) if preset_fields: for fname, field in preset_fields.items(): self.fields[fname] = field self.set_defaults() def clean(self): cleaned_data = self.cleaned_data self.makeQuery() return cleaned_data def set_defaults(self): """ Set default options on form (in event that it hasn't been requested yet. """ self.initial_data = dict([(name, unicode(field.initial)) for name, field in self.fields.items()]) self.makeQuery() return # TODO: make custom validators/fields? re django.core.validators # http://docs.djangoproject.com/en/dev/ref/forms/validation/ # # # # # # # Question classes # # # # # class Question(forms.Form): """ Question meta-class. Some methods will be moved in here which end up being common across question-types. For now this Question class works mostly unadulterated on LeksaQuestion and MorfaQuestion. Question.__init__() Validation process: Follows Django documentation, with custom versions of following: clean_answers clean Additional customization is in LeksaQuestion/MorfaQuestions' check_answer methods. When the form is validated, it runs clean_answers, and then clean. The clean method then calls check_answer() which does the actual answer checking, producing validation errors. """ # Shortcut hide = {'widget': forms.HiddenInput()} # Set up fields lemma = forms.CharField(max_length=50, **hide) pronoun = forms.CharField(max_length=8, required=False, **hide) userans = forms.CharField(max_length=50, required=False) word_id = forms.IntegerField(**hide) correct = forms.NullBooleanField(required=False, **hide) answers = forms.CharField(max_length=250, required=False, **hide) class Errors: """ Global question error responses. """ try_again = _(u'Try again!') empty_answers = _(u'No possible answers.') blank_user_answer = _(u'No answer given.') def __init__(self, *args, **kwargs): # Make compatible with old form names if kwargs.has_key('initial'): kwargs['initial']['word_id'] = kwargs['initial']['id'] kwargs['initial']['answers'] = ', '.join(kwargs['initial']['translations']) # Keep the lemma available in templates. self.lemma_value = kwargs['initial']['lemma'] if 'pronoun' in kwargs['initial']: self.pronoun_string = kwargs['initial']['pronoun'] else: pass super(Question, self).__init__(*args, **kwargs) def clean_answers(self): """ This method cleans answers from database, and will run before .clean() Here we try to cut off limits in Leksa entries, e.g.: tremenninger (innbyrdes) -> tremenninger For Morfa, this isn't necessary, as MorfaSettings.getInitialData supplies only lemmas matching tags: ['girjjis'] """ answers = self.cleaned_data.get("answers").split(', ') answers = [a.strip() for a in answers if a.strip()] # Remove parentheticals answers = [a.partition('(')[0].strip() for a in answers] if len(answers) == 0: raise forms.ValidationError(self.Errors.empty_answers) return answers def clean(self): """ Prepare form data and raise validation errors. Validation errors are raised if the user provides a wrong answer. Leksa and Morfa are essentially the same, since .GetInitialData() supplies the correct answers. This method depends on results from .clean_answers(), which runs first. """ cleaned_data = self.cleaned_data user_answer = cleaned_data.get("userans") answers = cleaned_data.get("answers") # Making sure that the lemma and answers always show up in the form. self.lemma_value = cleaned_data['lemma'] if 'pronoun' in cleaned_data: self.pronoun_string = cleaned_data['pronoun'] else: self.pronoun_string = '' try: self.answer_list = ', '.join(answers) except TypeError: print answers if type(answers) != list: raise Http404('Answers missing from one of the questions...?') self.answer_list_as_list = answers # Always return cleaned data. self.check_answer() return cleaned_data