LS55321
LS55321

Reputation: 883

How do you save the order of a django inline formset?

In Django, I'm using an inlineformset with can_order = True, on a model that has order_with_respect_to set. I've set up drag and drop on the front end, which results in Django's autogenerated ORDER form fields (which I've hidden) changing to reflect the new order. I've verified I'm POSTing the new order correctly to the server, but Django seems to ignore it, and saves the models in the original order. The automatically-created _order fields in the database never change.

How can I get Django to save the models using order specified in the formset? Do I need to do anything special other than calling save() on the formset?

Upvotes: 8

Views: 6270

Answers (2)

sirex
sirex

Reputation: 4911

Evan Borgstrom proposed solution does not work together with can_delete=True.

Here is my solution that also works with can_delete=True:

for instance in formset.save(commit=False):
    # ... do something with m2m relationships ...
for form in formset.ordered_forms:
    form.instance.order = form.cleaned_data['ORDER']
    form.instance.save()

Upvotes: 5

Evan Borgstrom
Evan Borgstrom

Reputation: 627

I had the same problem and after digging through the Django source figured that it's something you need to do on your own.

My original implementation looked something like this:

services = service_formset.save(commit=False)
for service in services:
    # ... do something with m2m relationships ...
    service.save()

However, as you've found this doesn't set the ORDER. So instead my implementation now looks like:

for form in service_formset:
    service = form.save(commit=False)
    # ... do something with m2m relationships ...
    service.order_order = form.cleaned_data['ORDER']
    service.save()

In my example above 'order_order' is the field I'm using to track order on my models.

Also remember that you need to specify the 'ordering' attribute of your model's Meta class to ensure that when you generate the formset again the elements are in the correct order.

class Service(models.Model):
    # ...
    order_order = models.IntegerField(default=0)
    class Meta:
        ordering = ['order_order',]

Upvotes: 2

Related Questions