Search code examples
djangodata-structuresmany-to-many

How to correctly use template tags in this specific Many-to-Many relationship in Django?


I've got the following Django many-to-many through model setup, but I can't seem to figure out how to iterate through each Container, get the list of checkboxes and if those checkboxes are true or false (CheckboxStatus.status).

The models are:

class Container(models.Model):
    name = models.CharField(max_length=200)
    checkboxes = models.ManyToManyField('Checkbox',
                                        through='CheckboxStatus',
                                        related_name='containers')

class Checkbox(models.Model):
    name = models.CharField(max_length=60)
    description = models.CharField(max_length=200)
    order = models.PositiveSmallIntegerField(default=0)

class CheckboxStatus(models.Model):
    container = models.ForeignKey(Container,
                                          related_name='checkboxstatus')
    checkbox = models.ForeignKey(Checkbox, related_name='checkboxstatus')
    status = models.NullBooleanField()

I've got the following where object_list = the CheckboxStatus model ...

{% for object in object_list. %}
    {{ object.container }}
    {{ object.checkbox }}
    {{ object.status }}
{% endfor %}

... but this results in all checkboxes, and I need to do some operations on each Container. In pseudocode, I'd like to have:

for container in object_list (where objectlist is "container"):
    container.id
    container.checkbox.id
    container.checkbox.status (unique for the container.id)

But maybe the relation is just plain wrong. Can some one push me in the right direction?


Solution

  • If I'm understanding this right, I don't think you need the through table. You should be able to define the ManyToManyField and then use a ModelForm and a CheckboxSelectMultiple widget to display the options as checkboxes.

    I changed the models to:

    class Container(models.Model):
        name = models.CharField(max_length=200)
        options = models.ManyToManyField('Option')
    
    # I changed the name of the Checkbox model to Option, for clarity.
    class Option(models.Model):
        name = models.CharField(max_length=60)
        description = models.CharField(max_length=200)
        order = models.PositiveSmallIntegerField(default=0)
    

    from forms.py:

    class ContainerOptionsForm(forms.ModelForm):
    class Meta:
        model = Container
        fields = ['options']
    
        widgets = {
            'options': forms.CheckboxSelectMultiple(),
        }
    

    Include the options form field in your template:

    {{ form.options }}
    

    If you need more control over the display of the options checkboxes, you can iterate over the options field of the form:

    {% for checkbox in form.options %}
        <label>{{ checkbox.choice_label }} {{ checkbox.tag }}</label>    
    {% endfor %}
    

    This should take care of it for a single container on a page. If you need to handle multiple containers on the same page, you will need to look into ModelFormSet.