Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing the display order of forms in a formset

Tags:

python

django

I am displaying a modelformset and I would like the forms to be ordered by the contents of one of its fields. So I want to use the equivalent of SomeModel.objects.filter(whatever).order_by('somefield') for a (model)formset in a template.

How can I do this?

Note that can_order does not do what I want (it must be automatic, not user specified). I have also tried other things, like the dictsort filter, but that produces unpredictable output (i.e. not ordered by the specified field).

I even tried {% regroup formset by somefield as sorted_formset %}, but the resulting sorted_formset cannot be used (iterated) as a normal formset.

like image 844
John Peters Avatar asked Nov 14 '12 21:11

John Peters


2 Answers

if you didn't defined Formset, this is the "inline code" version:

FS=inlineformset_factory(ParentClass,ChildClass)
formset=FS(instance=parentobject,
           queryset=parentobject.childobject_set.order_by("-time_begin")
          )
like image 71
phiree Avatar answered Oct 24 '22 08:10

phiree


To complete the answers. There are two ways how you can control the order of forms in the formset: formsets respect order of given queryset (this is shown in other replies). Another way (if you want to have the order of the forms fully under control) is to define custom formset class and override __iter__ and __getitem__ methods:

from django.forms import BaseModelFormSet

class MyModelBaseFormset(BaseModelFormSet):
    def __iter__(self):
        """Yields the forms in the order they should be rendered"""
        return ...

    def __getitem__(self, index):
        """Returns the form at the given index, based on the rendering order"""
        return ...


MyModelFormset = modelformset_factory(model=MyModel, formset=MyModelBaseFormset, queryset=...)

This approach is described in the Django documentation:

Iterating over the formset will render the forms in the order they were created. You can change this order by providing an alternate implementation for the __iter__() method.

Formsets can also be indexed into, which returns the corresponding form. If you override __iter__, you will need to also override __getitem__ to have matching behavior.

https://docs.djangoproject.com/en/dev/topics/forms/formsets/#django.forms.formsets.BaseFormSet

The example of implementing these methods is for example in this SO thread: modelformset __iter__ overloading problem.

like image 7
illagrenan Avatar answered Oct 24 '22 08:10

illagrenan