How to create a form field for every foreignkey in manytomany relationship in Django

Question:

I don’t understand how to build a specific form in Django.

First of all here are my models:

class Category(models.Model):
    name = models.CharField(max_length=200, unique=True)


class Assessment(models.Model):
    name = models.CharField(max_length=200)
    pub_date = models.DateTimeField(verbose_name=_('date published'), default=timezone.now)
    classgroup = models.ForeignKey(ClassGroup, verbose_name=_('class'), on_delete=models.CASCADE, related_name='+')
    category = models.ManyToManyField(Category, through='AssessmentScale', through_fields=('assessment', 'category'),)
    total = models.IntegerField()


class AssessmentScale(models.Model):
    assessment = models.ForeignKey(Assessment, on_delete=models.CASCADE)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    value = models.IntegerField()

I would like to have a form like this html form. Actually, an assessment scale is sub-divided into different categories. So when I create an assessment, I’d like have a form field for each category allowing to add a value via my custom intermediary model AssessmentScale. But I really don’t know the Django way to build this form. I read this post, which is similar I think, and someone advised the use of Inline model formsets. But I don’t understand how to solve my problem with the latter. Could you help me?

Asked By: Zogsha

||

Answers:

I had no answer from Stackoverflow but a friend of mine solved my problem like this with inline formset:

# forms.py
class AssessmentForm(ModelForm):
    class Meta:
        model = Assessment
        exclude = ('category',)


CategoryAssessmentFormSet = inlineformset_factory(
    Assessment,
    Assessment.category.through,
    fields=['category', 'value'],
    can_delete=False,
    extra=Category.objects.count(),
    max_num=Category.objects.count(),
    widgets={'category': Select(attrs={'hidden': 'true'})}
)

in my view, to render the formset:

# views.py
initial = [{'category': category} for category in Category.objects.all()]
formset = CategoryAssessmentFormSet(initial=initial)

Select is hidden but I still want the name of the selected field, in my template:

# template
{{ formset.management_form }}
{% for form in formset %}
    <div class="p-2">
        {% for value,selected in form.fields.category.choices %}
            {% if value == form.category.value %}{{ selected }}{% endif %}
        {% endfor %}
        {{ form.category }}
    </div>
    <div>
        {{ form.value}}
    </div>
{% endfor %}
Answered By: Zogsha
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.