Exemplo n.º 1
0
 def getInitialLinkDataFields(self):
     """
     Returns a dict mapping fields to be pre-populated with the corresponding model and model-field
     """
     initial = {}
     for section in self.page:
         for field in section:
             ftype = field['field_type']
             if cf_cache.isLinkField(ftype):
                 field_name = 'question_%d' % field['id']
                 initial[field_name] = {
                     'model': cf_cache.modelForLinkField(ftype)
                 }
                 """
                 if 'combo' in link_fields[ftype]:
                     initial[field_name]['field']=[]
                     for f in link_fields[ftype]['combo']:
                         initial[field_name]['field'].append(link_fields[f]['model_field'])
                 else:
                 """
                 model_field = cf_cache.getLinkFieldData(
                     ftype)['model_field']
                 if cf_cache.isCompoundLinkField(
                         initial[field_name]['model'], model_field):
                     model_field = cf_cache.getCompoundLinkFields(
                         initial[field_name]['model'], model_field)
                 initial[field_name]['model_field'] = model_field
     return initial
Exemplo n.º 2
0
 def getInitialLinkDataFields(self):
     """
     Returns a dict mapping fields to be pre-populated with the corresponding model and model-field
     """
     initial = {}
     for section in self.page:
         for field in section:
             ftype = field['field_type']
             if cf_cache.isLinkField(ftype):
                 field_name = 'question_%d' % field['id']
                 initial[field_name] = {'model': cf_cache.modelForLinkField(ftype)}
                 """
                 if 'combo' in link_fields[ftype]:
                     initial[field_name]['field']=[]
                     for f in link_fields[ftype]['combo']:
                         initial[field_name]['field'].append(link_fields[f]['model_field'])
                 else:
                 """
                 model_field = cf_cache.getLinkFieldData(ftype)['model_field']
                 if cf_cache.isCompoundLinkField(initial[field_name]['model'], model_field):
                     model_field = cf_cache.getCompoundLinkFields(initial[field_name]['model'], model_field)
                 initial[field_name]['model_field'] = model_field
     return initial
Exemplo n.º 3
0
    def getResponseData(self, form):
        """
        Returns the response data for this form, along with the questions
        """
        dmh = DMH(form=form)
        dyn = dmh.createDynModel()
        response_data = {'questions': [], 'answers': []}
        responses = dyn.objects.all().order_by('id').values()
        fields = Field.objects.filter(form=form).order_by('section__page__seq', 'section__seq', 'seq').values('id', 'field_type', 'label')
        
        # Let's first do a bit of introspection to figure out
        # what the linked models are, and what values need to be added to the
        # response data from these linked models.
        # And since we're already iterating over fields,
        # let's also set the questions in the process.
        add_fields = {}
        
        # Add in the user column if form is not anonymous
        if not form.anonymous:
            response_data['questions'].append(['user_id', 'User', 'fk'])
            
        # Add in the column for link fields, if any
        if form.link_type != "-1":
            only_fkey_model = cf_cache.only_fkey_models[form.link_type]
            response_data['questions'].append(["link_%s_id" % only_fkey_model.__name__, form.link_type, 'fk'])
        else:
            only_fkey_model = None      
        
        for field in fields:
            # I'll do a lot of merging here later
            qname = 'question_%d' % field['id']
            ftype = field['field_type']
            if cf_cache.isLinkField(ftype):
                # Let's grab the model first
                model = cf_cache.modelForLinkField(ftype)
                
                # Now let's see what fields need to be set
                add_fields[qname] = [model, cf_cache.getLinkFieldData(ftype)['model_field']]
                response_data['questions'].append([qname, field['label'], ftype])
                # Include this field only if it isn't a dummy field
            elif generic_fields[ftype]['typeMap'] is not DummyField:
                response_data['questions'].append([qname, field['label'], ftype])
            
        # Now let's set up the responses
        for response in responses:
            link_instances_cache={}
            
            # Add in user if form is not anonymous
            if not form.anonymous:
                response['user_id'] = unicode(response['user_id'])
                
            # Add in links
            if only_fkey_model is not None:
                if only_fkey_model.objects.filter(pk=response["link_%s_id" % only_fkey_model.__name__]).exists():
                    inst = only_fkey_model.objects.get(pk=response["link_%s_id" % only_fkey_model.__name__])
                else: inst = None    
                response["link_%s_id" % only_fkey_model.__name__] = unicode(inst)

            # Now, put in the additional fields in response
            for qname, data in add_fields.items():
                if data[0].__name__ not in link_instances_cache:
                    if data[0].objects.filter(pk=response["link_%s_id" % data[0].__name__]).exists():
                        link_instances_cache[data[0].__name__] = data[0].objects.get(pk=response["link_%s_id" % data[0].__name__])
                    else:
                        link_instances_cache[data[0].__name__] = None
                            
                if cf_cache.isCompoundLinkField(data[0], data[1]):
                    if link_instances_cache[data[0].__name__] is None:
                        response[qname] = []
                    else:    
                        response[qname] = [link_instances_cache[data[0].__name__].__dict__[x] for x in cf_cache.getCompoundLinkFields(data[0], data[1])]
                else:
                    if link_instances_cache[data[0].__name__] is None:
                        response[qname]=''
                    else:    
                        response[qname] = link_instances_cache[data[0].__name__].__dict__[data[1]]    
                
        # Add responses to response_data
        response_data['answers'].extend(responses)                                    
                    
        return response_data
Exemplo n.º 4
0
    def done(self, form_list, **kwargs):
        data = {}
        dyn = DMH(form=self.form)
        dynModel = dyn.createDynModel()
        fields = dict(dyn.fields)
        link_models_cache = {}
        
        # Plonking in user_id if the form is non-anonymous
        if not self.form.anonymous:
            data['user'] = self.curr_request.user
        
        # Populating data with the values that need to be inserted
        for form in form_list:
            for k,v in form.cleaned_data.items():
                # Check for only_fkey link models first
                if k.split('_')[1] in cf_cache.only_fkey_models:
                    data[k] = v
                    continue
                    
                field_id = int(k.split("_")[1])
                ftype = fields[field_id]

                # Now check for link fields
                if cf_cache.isLinkField(ftype):
                    model = cf_cache.modelForLinkField(ftype)
                    if model.__name__ not in link_models_cache:
                        link_models_cache[model.__name__] = {'model': model, 'data': {}}
                        pre_instance = self.form_handler.getInstanceForLinkField(k, model)
                        if pre_instance is not None:
                            link_models_cache[model.__name__]['instance'] = pre_instance
                        else:    
                            link_models_cache[model.__name__]['instance'] = getattr(model, 'cf_link_instance')(self.curr_request)
                    ftype_parts = ftype.split('_')
                    if len(ftype_parts) > 1 and cf_cache.isCompoundLinkField(model, '_'.join(ftype_parts[1:])):
                        #   Try to match a model field to the last part of the key we have.
                        partial_field_name = str(field_id).join(k.split(str(field_id))[1:]).lstrip('_')
                        target_fields = cf_cache.getCompoundLinkFields(model, '_'.join(ftype_parts[1:]))
                        for f in target_fields:
                            if f.endswith(partial_field_name):
                                model_field = f
                                break
                    else:
                        model_field = cf_cache.getLinkFieldData(ftype)['model_field']
                    link_models_cache[model.__name__]['data'].update({model_field: v}) 
                else:
                    data[k] = v
        
        # Create/update instances corresponding to link fields
        # Also, populate 'data' with foreign-keys that need to be inserted into the response table
        for k,v in link_models_cache.items():
            if v['instance'] is not None:
                # TODO-> the following update won't work for fk fields.
                v['instance'].__dict__.update(v['data'])
                v['instance'].save()
                curr_instance = v['instance']
            else:
                try:
                    new_instance = v['model'].objects.create(**v['data'])
                except:    
                    # show some error message
                    pass
            if v['instance'] is not None:
                data['link_%s' % v['model'].__name__] = v['instance']                
        
        # Saving response
        initial_keys = data.keys()
        for key in initial_keys:
            #   Check that we didn't already handle this value as a linked field
            if key.split('_')[0] in cf_cache.link_fields:
                del data[key]
            #   Check that this value didn't come from a dummy field
            if key.split('_')[0] == 'question' and generic_fields[fields[int(key.split('_')[1])]]['typeMap'] == DummyField:
                del data[key]
        dynModel.objects.create(**data)    
        return HttpResponseRedirect('/customforms/success/%d/' % self.form.id)
Exemplo n.º 5
0
    def _getFields(self):
        """
        Sets self.fields and self.fieldsets for this page
        """
        model_fields_cache = {}
        for section in self.page:
            curr_fieldset = []
            curr_fieldset.extend([section[0]['section__title'], {'fields':[], 'classes':['section',]}])
            curr_fieldset[1]['description'] = section[0]['section__description']
            
            # Check for only_fkey models.
            # If any, insert the relevant field into the first section of the fist page
            if section[0]['section__seq'] == 0 and self.seq == 0:
                if self.form.link_type != '-1':
                    label = 'Please pick the %s you want to fill the form for' % self.form.link_type
                    link_cls = cf_cache.only_fkey_models[self.form.link_type]
                    if self.form.link_id == -1:
                        # User needs to be shown a list of instances from which to select
                        queryset = link_cls.objects.all()
                        widget = forms.Select()
                    else:
                        queryset = link_cls.objects.filter(pk=self.form.link_id)
                        widget = forms.HiddenInput()    
                    fld = forms.ModelChoiceField(queryset = queryset, label = label, initial = queryset[0], 
                                                widget = widget, required = True, empty_label = None)
                    self.fields.append(['link_%s' % link_cls.__name__, fld ])
                    curr_fieldset[1]['fields'].append('link_%s' % link_cls.__name__)        
            
            for field in section:
                field_name = 'question_%d' % field['id']
                field_attrs = {'label': field['label'], 'help_text': field['help_text'], 'required': field['required']}
                
                # Setting the 'name' attribute for combo fields
                """
                if field['field_type'] in self._combo_fields:
                    field_attrs['name']=field_name
                """    

                #   Extract form attributes for further use below
                other_attrs = []
                for attr_name in field['attributes']:
                    other_attrs.append({'attr_type': attr_name, 'value': field['attributes'][attr_name]})
                    
                    #   Create dynamic validators to check results if the correct answer has
                    #   been specified by the form author
                    if attr_name == 'correct_answer' and len(field['attributes'][attr_name].strip()) > 0:
                        if field['field_type'] in ['dropdown', 'radio']:
                            value_choices = field['attributes']['options'].split('|')
                            target_value = value_choices[int(field['attributes'][attr_name])]
                        elif field['field_type'] in ['checkboxes']:
                            value_choices = field['attributes']['options'].split('|')
                            target_value = [value_choices[int(index)] for index in field['attributes'][attr_name].split(',')]
                        else:
                            target_value = field['attributes'][attr_name]

                        field_attrs['validators'] = [matches_answer(target_value)]

                if other_attrs:
                    field_attrs.update(self._getAttrs(other_attrs))
                    
                # First, check for link fields
                if cf_cache.isLinkField(field['field_type']):
                    # Get all form fields for this model, if it hasn't already been done
                    link_model = cf_cache.modelForLinkField(field['field_type'])
                    if not link_model:
                        continue
                    if link_model.__name__ not in model_fields_cache:
                        model_fields_cache[link_model.__name__] = {}
                        model_fields_cache[link_model.__name__].update(fields_for_model(link_model, widgets=getattr(link_model, 'link_fields_widgets', None)))

                    model_field = cf_cache.getLinkFieldData(field['field_type'])['model_field']
                    
                    field_is_custom = False
                    if model_field in model_fields_cache[link_model.__name__]:
                        form_field = model_fields_cache[link_model.__name__][model_field]
                    else:
                        #   See if there's a custom field
                        if model_field in custom_fields:
                            form_field = cf_cache.getCustomFieldInstance(model_field, field_name)
                            field_is_custom = True
                        else:
                            raise Exception('Could not find linked field: %s' % model_field)

                    # TODO -> enforce "Required" constraint server-side as well, or trust the client-side code?
                    form_field.__dict__.update(field_attrs)
                    form_field.widget.attrs.update({'class': ''})
                    if form_field.required:
                        # Add a class 'required' to the widget
                        form_field.widget.attrs['class'] += 'required ' 
                        form_field.widget.is_required = True

                    if not field_is_custom:
                        # Add in other classes for validation
                        generic_type = cf_cache.getGenericType(form_field)
                        if 'widget_attrs' in self._field_types[generic_type] and 'class' in self._field_types[generic_type]['widget_attrs']:
                            form_field.widget.attrs['class'] += self._field_types[generic_type]['widget_attrs']['class']    

                    # Adding to field list
                    self.fields.append([field_name, form_field])
                    curr_fieldset[1]['fields'].append(field_name)
                    continue    
                
                # Generic field                                
                widget_attrs = {}    
                if 'attrs' in self._field_types[field['field_type']]:
                    field_attrs.update(self._field_types[field['field_type']]['attrs'])
                if 'widget_attrs' in self._field_types[field['field_type']]:
                    widget_attrs.update(self._field_types[field['field_type']]['widget_attrs'])
                typeMap = self._field_types[field['field_type']]['typeMap']
                
                # Setting classes required for front-end validation
                if field['required']:
                    widget_attrs['class'] += ' required'
                if 'min_value' in field_attrs:
                    widget_attrs['min'] = field_attrs['min_value']
                if 'max_value' in field_attrs:
                    widget_attrs['max'] = field_attrs['max_value']
                if 'min_length' in field_attrs:
                    widget_attrs['minlength'] = field_attrs['min_length']
                if 'max_length' in field_attrs:
                    widget_attrs['maxlength'] = field_attrs['max_length']
                if 'min_words' in field_attrs:
                    widget_attrs['minWords'] = field_attrs['min_words']
                if 'max_words' in field_attrs:
                    widget_attrs['maxWords'] = field_attrs['max_words']                    
            
                # For combo fields, classes need to be passed in to the field
                if field['field_type'] in self._combo_fields:
                    field_attrs.update(widget_attrs)
                    
                # Setting the queryset for a courses field
                if field['field_type'] == 'courses':
                    if self.form.link_type == 'program' or self.form.link_type == 'Program':
                        field_attrs['queryset'] = Program.objects.get(pk = self.form.link_id).classsubject_set.all()
                        
                # Initializing widget                
                if field_attrs['widget'] is not None:
                    try:
                        field_attrs['widget'] = field_attrs['widget'](attrs = widget_attrs)
                    except KeyError:
                        pass
                    
                self.fields.append([field_name, typeMap(**field_attrs) ])
                curr_fieldset[1]['fields'].append(field_name)            

            self.fieldsets.append(tuple(curr_fieldset))
Exemplo n.º 6
0
    def getResponseData(self, form):
        """
        Returns the response data for this form, along with the questions
        """
        dmh = DMH(form=form)
        dyn = dmh.createDynModel()
        response_data = {'questions': [], 'answers': []}
        responses = dyn.objects.all().order_by('id').values()
        fields = Field.objects.filter(form=form).order_by('section__page__seq', 'section__seq', 'seq').values('id', 'field_type', 'label')

        # Let's first do a bit of introspection to figure out
        # what the linked models are, and what values need to be added to the
        # response data from these linked models.
        # And since we're already iterating over fields,
        # let's also set the questions in the process.
        add_fields = {}

        # Add in the user column if form is not anonymous
        if not form.anonymous:
            response_data['questions'].append(['user_id', 'User ID', 'fk'])
            response_data['questions'].append(['user_display', 'User', 'textField'])
            response_data['questions'].append(['user_email', 'User e-mail', 'textField'])
            response_data['questions'].append(['username', 'Username', 'textField'])

        # Add in the column for link fields, if any
        if form.link_type != "-1":
            only_fkey_model = cf_cache.only_fkey_models[form.link_type]
            response_data['questions'].append(["link_%s_id" % only_fkey_model.__name__, form.link_type, 'fk'])
        else:
            only_fkey_model = None

        for field in fields:
            # I'll do a lot of merging here later
            qname = 'question_%d' % field['id']
            ftype = field['field_type']
            if cf_cache.isLinkField(ftype):
                # Let's grab the model first
                model = cf_cache.modelForLinkField(ftype)

                # Now let's see what fields need to be set
                add_fields[qname] = [model, cf_cache.getLinkFieldData(ftype)['model_field']]
                response_data['questions'].append([qname, field['label'], ftype])
                # Include this field only if it isn't a dummy field
            elif generic_fields[ftype]['typeMap'] is not DummyField:
                response_data['questions'].append([qname, field['label'], ftype])

        users = ESPUser.objects.in_bulk(map(lambda response: response['user_id'], responses))

        # Now let's set up the responses
        for response in responses:
            link_instances_cache={}

            # Add in user if form is not anonymous
            if not form.anonymous:
                user = users[response['user_id']]
                response['user_id'] = unicode(response['user_id'])
                response['user_display'] = user.name()
                response['user_email'] = user.email
                response['username'] = user.username

            # Add in links
            if only_fkey_model is not None:
                if only_fkey_model.objects.filter(pk=response["link_%s_id" % only_fkey_model.__name__]).exists():
                    inst = only_fkey_model.objects.get(pk=response["link_%s_id" % only_fkey_model.__name__])
                else: inst = None
                response["link_%s_id" % only_fkey_model.__name__] = unicode(inst)

            # Now, put in the additional fields in response
            for qname, data in add_fields.items():
                if data[0].__name__ not in link_instances_cache:
                    if data[0].objects.filter(pk=response["link_%s_id" % data[0].__name__]).exists():
                        link_instances_cache[data[0].__name__] = data[0].objects.get(pk=response["link_%s_id" % data[0].__name__])
                    else:
                        link_instances_cache[data[0].__name__] = None

                if cf_cache.isCompoundLinkField(data[0], data[1]):
                    if link_instances_cache[data[0].__name__] is None:
                        response[qname] = []
                    else:
                        response[qname] = [link_instances_cache[data[0].__name__].__dict__[x] for x in cf_cache.getCompoundLinkFields(data[0], data[1])]
                else:
                    if link_instances_cache[data[0].__name__] is None:
                        response[qname]=''
                    else:
                        response[qname] = link_instances_cache[data[0].__name__].__dict__[data[1]]

        # Add responses to response_data
        response_data['answers'].extend(responses)

        return response_data
Exemplo n.º 7
0
    def done(self, form_list, **kwargs):
        data = {}
        dyn = DMH(form=self.form)
        dynModel = dyn.createDynModel()
        fields = dict(dyn.fields)
        link_models_cache = {}

        # Plonking in user_id if the form is non-anonymous
        if not self.form.anonymous:
            data['user'] = self.curr_request.user

        # Populating data with the values that need to be inserted
        for form in form_list:
            for k,v in form.cleaned_data.items():
                # Check for only_fkey link models first
                if k.split('_')[1] in cf_cache.only_fkey_models:
                    data[k] = v
                    continue

                field_id = int(k.split("_")[1])
                ftype = fields[field_id]

                # Now check for link fields
                if cf_cache.isLinkField(ftype):
                    model = cf_cache.modelForLinkField(ftype)
                    if model.__name__ not in link_models_cache:
                        link_models_cache[model.__name__] = {'model': model, 'data': {}}
                        pre_instance = self.form_handler.getInstanceForLinkField(k, model)
                        if pre_instance is not None:
                            link_models_cache[model.__name__]['instance'] = pre_instance
                        else:
                            link_models_cache[model.__name__]['instance'] = getattr(model, 'cf_link_instance')(self.curr_request)
                    ftype_parts = ftype.split('_')
                    if len(ftype_parts) > 1 and cf_cache.isCompoundLinkField(model, '_'.join(ftype_parts[1:])):
                        #   Try to match a model field to the last part of the key we have.
                        partial_field_name = str(field_id).join(k.split(str(field_id))[1:]).lstrip('_')
                        target_fields = cf_cache.getCompoundLinkFields(model, '_'.join(ftype_parts[1:]))
                        for f in target_fields:
                            if f.endswith(partial_field_name):
                                model_field = f
                                break
                    else:
                        model_field = cf_cache.getLinkFieldData(ftype)['model_field']
                    link_models_cache[model.__name__]['data'].update({model_field: v})
                else:
                    data[k] = v

        # Create/update instances corresponding to link fields
        # Also, populate 'data' with foreign-keys that need to be inserted into the response table
        for k,v in link_models_cache.items():
            if v['instance'] is not None:
                # TODO-> the following update won't work for fk fields.
                v['instance'].__dict__.update(v['data'])
                v['instance'].save()
                curr_instance = v['instance']
            else:
                try:
                    new_instance = v['model'].objects.create(**v['data'])
                except:
                    # show some error message
                    pass
            if v['instance'] is not None:
                data['link_%s' % v['model'].__name__] = v['instance']

        # Saving response
        initial_keys = data.keys()
        for key in initial_keys:
            #   Check that we didn't already handle this value as a linked field
            if key.split('_')[0] in cf_cache.link_fields:
                del data[key]
            #   Check that this value didn't come from a dummy field
            if key.split('_')[0] == 'question' and generic_fields[fields[int(key.split('_')[1])]]['typeMap'] == DummyField:
                del data[key]
        dynModel.objects.create(**data)
        return HttpResponseRedirect('/customforms/success/%d/' % self.form.id)
Exemplo n.º 8
0
    def _getFields(self):
        """
        Sets self.fields and self.fieldsets for this page
        """
        model_fields_cache = {}
        for section in self.page:
            curr_fieldset = []
            curr_fieldset.extend([section[0]['section__title'], {'fields':[], 'classes':['section',]}])
            curr_fieldset[1]['description'] = section[0]['section__description']

            # Check for only_fkey models.
            # If any, insert the relevant field into the first section of the fist page
            if section[0]['section__seq'] == 0 and self.seq == 0:
                if self.form.link_type != '-1':
                    label = 'Please pick the %s you want to fill the form for' % self.form.link_type
                    link_cls = cf_cache.only_fkey_models[self.form.link_type]
                    if self.form.link_id == -1:
                        # User needs to be shown a list of instances from which to select
                        queryset = link_cls.objects.all()
                        widget = forms.Select()
                    else:
                        queryset = link_cls.objects.filter(pk=self.form.link_id)
                        widget = forms.HiddenInput()
                    fld = forms.ModelChoiceField(queryset = queryset, label = label, initial = queryset[0],
                                                widget = widget, required = True, empty_label = None)
                    self.fields.append(['link_%s' % link_cls.__name__, fld ])
                    curr_fieldset[1]['fields'].append('link_%s' % link_cls.__name__)

            for field in section:
                field_name = 'question_%d' % field['id']
                field_attrs = {'label': field['label'], 'help_text': field['help_text'], 'required': field['required']}

                # Setting the 'name' attribute for combo fields
                """
                if field['field_type'] in self._combo_fields:
                    field_attrs['name']=field_name
                """

                #   Extract form attributes for further use below
                other_attrs = []
                for attr_name in field['attributes']:
                    other_attrs.append({'attr_type': attr_name, 'value': field['attributes'][attr_name]})

                    #   Create dynamic validators to check results if the correct answer has
                    #   been specified by the form author
                    if attr_name == 'correct_answer' and len(field['attributes'][attr_name].strip()) > 0:
                        if field['field_type'] in ['dropdown', 'radio']:
                            value_choices = field['attributes']['options'].split('|')
                            target_value = value_choices[int(field['attributes'][attr_name])]
                        elif field['field_type'] in ['checkboxes']:
                            value_choices = field['attributes']['options'].split('|')
                            target_value = [value_choices[int(index)] for index in field['attributes'][attr_name].split(',')]
                        else:
                            target_value = field['attributes'][attr_name]

                        field_attrs['validators'] = [matches_answer(target_value)]

                if other_attrs:
                    field_attrs.update(self._getAttrs(other_attrs))

                # First, check for link fields
                if cf_cache.isLinkField(field['field_type']):
                    # Get all form fields for this model, if it hasn't already been done
                    link_model = cf_cache.modelForLinkField(field['field_type'])
                    if not link_model:
                        continue
                    if link_model.__name__ not in model_fields_cache:
                        model_fields_cache[link_model.__name__] = {}
                        model_fields_cache[link_model.__name__].update(fields_for_model(link_model, widgets=getattr(link_model, 'link_fields_widgets', None)))

                    model_field = cf_cache.getLinkFieldData(field['field_type'])['model_field']

                    field_is_custom = False
                    if model_field in model_fields_cache[link_model.__name__]:
                        form_field = model_fields_cache[link_model.__name__][model_field]
                    else:
                        #   See if there's a custom field
                        if model_field in custom_fields:
                            form_field = cf_cache.getCustomFieldInstance(model_field, field_name)
                            field_is_custom = True
                        else:
                            raise Exception('Could not find linked field: %s' % model_field)

                    # TODO -> enforce "Required" constraint server-side as well, or trust the client-side code?
                    form_field.__dict__.update(field_attrs)
                    form_field.widget.attrs.update({'class': ''})
                    if form_field.required:
                        # Add a class 'required' to the widget
                        form_field.widget.attrs['class'] += 'required '
                        form_field.widget.is_required = True

                    if not field_is_custom:
                        # Add in other classes for validation
                        generic_type = cf_cache.getGenericType(form_field)
                        if 'widget_attrs' in self._field_types[generic_type] and 'class' in self._field_types[generic_type]['widget_attrs']:
                            form_field.widget.attrs['class'] += self._field_types[generic_type]['widget_attrs']['class']

                    # Adding to field list
                    self.fields.append([field_name, form_field])
                    curr_fieldset[1]['fields'].append(field_name)
                    continue

                # Generic field
                widget_attrs = {}
                if 'attrs' in self._field_types[field['field_type']]:
                    field_attrs.update(self._field_types[field['field_type']]['attrs'])
                if 'widget_attrs' in self._field_types[field['field_type']]:
                    widget_attrs.update(self._field_types[field['field_type']]['widget_attrs'])
                typeMap = self._field_types[field['field_type']]['typeMap']

                # Setting classes required for front-end validation
                if field['required']:
                    widget_attrs['class'] += ' required'
                if 'min_value' in field_attrs:
                    widget_attrs['min'] = field_attrs['min_value']
                if 'max_value' in field_attrs:
                    widget_attrs['max'] = field_attrs['max_value']
                if 'min_length' in field_attrs:
                    widget_attrs['minlength'] = field_attrs['min_length']
                if 'max_length' in field_attrs:
                    widget_attrs['maxlength'] = field_attrs['max_length']
                if 'min_words' in field_attrs:
                    widget_attrs['minWords'] = field_attrs['min_words']
                if 'max_words' in field_attrs:
                    widget_attrs['maxWords'] = field_attrs['max_words']

                # For combo fields, classes need to be passed in to the field
                if field['field_type'] in self._combo_fields:
                    field_attrs.update(widget_attrs)

                # Setting the queryset for a courses field
                if field['field_type'] == 'courses':
                    if self.form.link_type == 'program' or self.form.link_type == 'Program':
                        field_attrs['queryset'] = Program.objects.get(pk = self.form.link_id).classsubject_set.all()

                # Initializing widget
                if field_attrs['widget'] is not None:
                    try:
                        field_attrs['widget'] = field_attrs['widget'](attrs = widget_attrs)
                    except KeyError:
                        pass

                self.fields.append([field_name, typeMap(**field_attrs) ])
                curr_fieldset[1]['fields'].append(field_name)

            self.fieldsets.append(tuple(curr_fieldset))