'Django Forms - How would I implement a form that dynamically changes its fields depending on model objects in the database?

I have 3 models :

from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    pass

class Certification(models.Model):
    def __str__(self):
        return f'{self.name}'
    name = models.CharField(max_length=30)
    shortName = models.CharField(max_length=10)
    score = models.IntegerField(null=True, blank=True)


class ActiveCertification(models.Model):
    def __str__(self):
        return f'{self.user} | {self.sensor}'
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    certification = models.ForeignKey(Certification, on_delete=models.CASCADE)
    value = models.BooleanField()

In my database, there are a few different Certification objects, but there is bound to be more in the future.

My ActiveCertification model is used to identify which user has which certification.

Now, the problem I am facing is that I wish that each user could fill out which certifications they have in a form. I basically need the form to look like this :

Certification 1 [ ]
Certification 2 [ ]
Certification 3 [ ]
Certification 4 [ ]
ect...
[ Submit ]

([ ] representing a checkbox)

Basically, I need that when user A uses this form, he checks the certifications he has, and that upon submitting, the ActiveCertification table would fill/update the userA/certification pairs.

At first, I started doing a form like this :

from django import forms

class ActiveCertificationForm(forms.Form):
    certification1 = forms.BooleanField(required=False)
    certification2 = forms.BooleanField(required=False)
    certification3 = forms.BooleanField(required=False)
    certification4 = forms.BooleanField(required=False)

But quickly realized that this is a terrible solution, as when new certifications would be added to the database, the form wouldn't automatically update.

I tried looking in the Django documentation for help, and tried to implement the form with the ModelChoiceField field, but it doesn't really work, as it produces a dropdown list, and I need a checkbox list.

Any help would be greatly appreciated. Thanks in advance !



Solution 1:[1]

There are two possibilities:

model formsets and using a forms.ModelMultipleChoiceField with a CheckBoxSelectMultiple widget.

formsets

forms.py:

from django.forms import modelformset_factory

from yourapp.models import ActiveCertification


ActiveCertificationFormSet = modelformset_factory(ActiveCertification, fields=('certification', 'value',))

views.py

from django.shortcuts import render
from yourapp.forms import ActiveCertificationFormSet
from yourapp.models import ActiveCertification

def your_view(request, *args, **kwargs):
    active_certs = ActiveCertivication.objects.filter(user=request.user)
    context = {
        'certification_formset': ActiveCertificationFormSet(
            queryset=active_certs,
        ),
    }
    return render(request, 'certification_template.html', context)

ModelMultipleChoiceField

from django import forms

class CertificationForm(forms.Form):
    certifications = forms.ModelMultipleChoiceField(
        widget=forms.CheckBoxSelectMultiple(),
    )

See the respective documentation linked above for more details.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 SMoenig