1

I have a "Parent" model, which contains multiple "Child" models and the relationship between Parent and Child holds the order of the children. Thus, I need a custom intermediary model.

models.py:

class Parent(models.Model):
    name = models.CharField
    children = models.ManyToManyField(Child, through=ParentChild)
    ...

class Child(models.Model):
    name = models.CharField()
    ...

class ParentChild(model.Model):
    parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
    child = models.ForeignKey(Child, on_delete=models.CASCADE)
    order_of_child = IntegerField(null=True, blank=True, unique=True, default=None) 

A Parent object is created based on a form and the Child objects to be part of the Parent object are selected by checkboxes. Now my questions are: How can the order_of_child be included in the form and rendered alongside the checkboxes and how can the relationship be correctly saved in the view?

forms.py:

class ParentForm(ModelForm):

    class Meta:
        model = Parent
        fields = ['name', 'children']

    def __init__(self, *args, **kwargs):
        super(ParentForm, self).__init__(*args, **kwargs)
        self.fields['name'] = forms.CharField(label='Name', widget=forms.TextInput()
        self.fields['children'] = ModelMultipleChoiceField(
                                      widget=forms.CheckboxSelectMultiple(queryset=Child.objects.all())
Anubis
  • 11
  • 1

1 Answers1

1

To save the relationship, you just first create and save the Parent, then loop through form.cleaned_data['children'] to create each ParentChild instance, assigning the index of the loop as the order.

Now for the order, that's more tricky, you'll need a widget that allows you to reorder the selection, so the default CheckboxSelectMultiple won't work because it doesn't do that. You need some javascript for that: Copy the selected options to a new div where the user can drag & drop to change the order, e.g. using a library such as jquery.ui.sortable or sortableJS/sortable. With javascript, you populate a hidden field with the selected values in the right order, which is what you submit in the end.

There's also a special django sortable multiselectfield package which I haven't tried (uses jqueryUI for sorting).

dirkgroten
  • 20,112
  • 2
  • 29
  • 42