Source code for apps.questionnaire.forms

"""
This module contains the baseclass for all questionnaire forms
and the functions for getting all forms based on a questionnaire model
class.

To add a new form, a new apps needs to be added including a models.py with the
new questionnaire model and a forms.py file with all the new forms.

.. note:: Make sure to update the PACKAGE_LOCATION dict in models.py

Forms can be defined as the following the example:

.. code-block:: python

    class IDBQuestionnaireForm3A(BaseQuestionnaireForm):
        #Forms need to subclass BaseQuestionnaireForm.

        #The form_template which is used rendering the template
        form_template = 'questionnaire/DefaultQuestionnaireForm.html'

        #The number of the form. This number is used to sort the
        #forms when they are retrieved for a model
        form_nr = 3

        #Condition method for conditionally showing the form (True=show)
        #Forms that are not shown are also not validated.
        #The provided wizard argument can be used to get the cleaned
        #data of a form like shown in the example below.
        def condition(self, wizard):
            cleaned_data = wizard.get_cleaned_data_for_form_class(
                IDBQuestionnaireForm)
            if cleaned_data:
                if 'has_stoma' in cleaned_data:
                    if cleaned_data['has_stoma'] == 'yes':
                        return False
            return True

        class Meta:
            model = IBDQuestionnaire

            fieldsets = (
                (None, {'fields': (
                    'stool_urgency', 'stool_planning', 'stool_continence',)}),
            )

            #By using the create_exclude_list method you only have to specify
            #the fieldsets. The excluded list is computed automatically based
            #on the fieldsets en model definition. For multiple forms for one
            #model this saves a lot of time & possibilities for errors.
            exclude = create_exclude_list(model, fieldsets)

The get_forms_for method automatically will pick up the new forms when
the package is added to the PACKAGE_LOCATION dict in models.py.

:subtitle:`Class definitions:`
"""
import inspect
import importlib
from core.forms import BaseModelForm
from apps.questionnaire.models import PACKAGE_LOCATION
# Definitions where to find the forms for every model
# so forms can be saved splitted up


[docs]def form_sorting_function(form): """ Simple sorting helper function Args: - form: a form instance Returns: The form_nr of the form. """ return form.form_nr
[docs]def get_forms_for(questionnaire_model_class): """ Helper function for getting all forms for a questionnaire model class. Args: - questionnaire_model_class: the class of the questionnaire model. Returns: A list of forms for a questionnaire model class, sorted on form_nr. """ forms = [] # import the form.py module from a package by getting # package name from the PACKAGE_LOCATION dict from models.py module_name =\ PACKAGE_LOCATION[questionnaire_model_class.__name__] + '.forms' module = importlib.import_module(module_name) # loop through all members and get the forms for the # questionnaire_model_class for name, obj in inspect.getmembers(module): if inspect.isclass(obj): if issubclass(obj, BaseQuestionnaireForm): if obj.Meta.model == questionnaire_model_class: forms.append(obj) # sort the forms based on form_nr forms.sort(key=form_sorting_function) return forms
[docs]def create_exclude_list(model, fieldsets): """ Helper method for automatic generating the exclude list of fields based on a model and a fieldset definition. Allows to only set the fieldsets attribute and use this function for the exclude list. Args: - model: the model to inspect for modelfields - fieldsets: the fieldsets that should be included Returns: A tuple with all model fields excluding the fields in fieldsets """ # Create set of fields to auto populate the exclude list fieldset_all_fields = ['id'] for l in fieldsets: for fieldset_field in l[1]['fields']: fieldset_all_fields.append(fieldset_field) exclude_list = [] # auto create the exclude list based on fieldsets above for field in model._meta.fields: if field.name not in fieldset_all_fields: exclude_list.append(field.name) return tuple(exclude_list)
[docs]class BaseQuestionnaireForm(BaseModelForm): ''' Base form for all questionnaires uses a form_nr attribute for sorting and a condition method for conditionally showing/using the form. ''' # The form_nr attribute is the order in which the forms are shown form_nr = 0 def __init__(self, *args, **kwargs): # Add patient to form self.patient = kwargs.pop('patient', None) super(BaseQuestionnaireForm, self).__init__(*args, **kwargs) # Use this function to set a condition # for showing the form (True=show form, False=don't show)
[docs] def condition(self, wizard): """ Override this function to allow conditional showing/using forms. If the form is not shown it is not validated. Args: - wizard: the wizard instance that is used to show the forms\ which can be used to get clean and unclean data of other steps/forms to determine if the form should be shown. Returns: True if the form should be used else False (default=True) """ return True
class Meta: # The model will be set in a subclass model = None