0

Something very strange is happening, I've built a MultipleChoiceField in forms.py that is rendering as a normal list. I am unable to have the checkboxes display. I'm hoping someone can spot where I might have gone wrong.

forms.py

from django import forms
from . import models
from behaviour.models import Interventions

class IncidentForm(forms.Form):

    def __init__(self,*args,**kwargs):
        self.request = kwargs.pop('request')
        super(IncidentForm,self).__init__(*args, **kwargs)

        intervention_set = Interventions.objects.filter(schoolid_id = self.request)
        intervention_choice = []
        for intervention in intervention_set:
            intervention_choice.append((intervention.pk, intervention.name))
        self.fields['intervention'].choices = intervention_choice

    intervention = forms.MultipleChoiceField(label='Intervention', choices=(), widget=forms.CheckboxSelectMultiple(), required=True,)

incident.html

<div>
    <label class="control-label">{% trans 'Intervention' %}</label><br />
    {{ form.intervention }}
    <small class="form-control-feedback"> {{ form.intervention.errors }} </small> 
</div>

HTML output

<div>
    <label class="control-label">Intervention</label><br>
    <ul id="id_intervention">
        <li><label for="id_intervention_0"><input type="checkbox" name="intervention" value="3" id="id_intervention_0">
        Communicate verbally with Parent</label>
        </li>
        <li><label for="id_intervention_1"><input type="checkbox" name="intervention" value="2" id="id_intervention_1">
        Non-verbal signal</label>
        </li>
        <li><label for="id_intervention_2"><input type="checkbox" name="intervention" value="1" id="id_intervention_2">
        Spoke with Student</label>
        </li>
    </ul>
    <small class="form-control-feedback">  </small> 
</div>

Screenshot of output

RJL
  • 1
  • 1
  • Try removing the `choices` from your widget. Or putting the options in the choices and let it render them. – Carl Brubaker May 12 '18 at 18:42
  • I was thinking about it more. You set choices in def init, then overwrite choices when you make your widget. Try making intervention_choices in your init, and the set the widget choices = intervention_choices – Carl Brubaker May 12 '18 at 22:42

1 Answers1

1

If you are using Django admin and you parent model is not using any relationship with child model but has charfield to store ids of selected items of child model that will be added to ModelAdmin as custom field.

Follow steps: STEP 1: model.py

   class yourparentmodel(models.Model):
        ...
    prior_learning_checks = models.CharField(max_length=120, null = True, blank=True)
        ...

class childmodel(models.Model):
   rpl_id = models.CharField(max_length=4, null = True, blank=True)
   rpl_desc = models.CharField(max_length=120, null = True, blank=True)

Here in this example parent is CohortDetails as inline to Cohort, or can limit to Cohort only if don't need inlines.

and child model is StudentRPL here in this example.

STEP 2: admin.py Add CheckboxSelectMultiple to list your table data that id and description in this example. Then use init attach your custom field for child model with parent form.

class StudentRPLForm(forms.ModelForm):

    student_prior_learning = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), queryset=StudentRpl.objects.all())

    class Meta:
        model = StudentRpl
        fields = [
                'rpl_indicator',
                'rpl_description',
               ]



 def __init__(self, *args, **kwargs):
            
            super(StudentRPLForm, self).__init__(*args, **kwargs)
    
            if self.instance and self.instance.pk:
                    self.fields['student_prior_learning']=forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), queryset=StudentRpl.objects.all())
                
                rpl_list = []
    
                ids = self.instance.prior_learning_checks
    
                if ',' in ids:
                    ids = ids[0:(len(ids) - 1)]
                    rpl_list = ids.rsplit(',')
                    self.fields['student_prior_learning'].initial = StudentRpl.objects.filter(rpl_indicator__in=rpl_list)

Now it is time to save data by overriding save(self, commit). Make sure use the cleaned_data. this is magic to collect only checked rows data and save to charfield of your parentmodel to read it again when to load the change_form. Because you are saving as comma separared ids, you have chance to load this string into list and filter your custom child model. Other magic to view last saved ids in commas by assigning: self.fields['student_prior_learning'].initial value to your filtered data in init function above (as i did)!!!

   def save(self, commit=True, *args, **kwargs):
       m = super(StudentRPLForm, self).save(commit=False, *args, **kwargs)

       selected_rpl_list = ''
       if self is not 'CohortDetailsForm':
            for cr in self.cleaned_data['student_prior_learning']:
            
                selected_rpl_list += cr.rpl_indicator + ','

        m.prior_learning_checks = selected_rpl_list

        if commit:
            m.save()

STEP 3: admin.py Assign your form to Inline or directly to modeladmin class if you don't need inlines.

class CohortDetailInline(admin.StackedInline):
    model = CohortDetails
    form = StudentRPLForm
    fieldsets = ['fields':, ('student_prior_learning')]
    .....


@admin.register(Cohort)
class CohortAdmin(admin.ModelAdmin):
      inlines = CohortDetailInline
      ....

DONE !!!!

G-2
  • 11
  • 1
  • 5