Search code examples
pythondjangopaginatorformsets

Paginate Django formset


I have a model formset that I want to display 10 forms at a time using Django's Paginator, but it can't be done like paginator = Paginator(formset, 10). What's the correct way to do this, if there is a way?


Solution

  • This is a generic example of the solution I found to my problem:

    In the forms.py file:

    class MyForm(ModelForm):
        class Meta:
            model = MyModel
            fields = ('description',)
    

    In the views.py file:

    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    
    FormSet = modelformset_factory(MyModel, form=MyForm, extra=0)
    if request.method == 'POST':
        formset = FormSet(request.POST, request.FILES)
        # Your validation and rest of the 'POST' code
    else:
        query = MyModel.objects.filter(condition)
        paginator = Paginator(query, 10) # Show 10 forms per page
        page = request.GET.get('page')
        try:
            objects = paginator.page(page)
        except PageNotAnInteger:
            objects = paginator.page(1)
        except EmptyPage:
            objects = paginator.page(paginator.num_pages)
        page_query = query.filter(id__in=[object.id for object in objects])
        formset = FormSet(queryset=page_query)
        context = {'objects': objects, 'formset': formset}
        return render_to_response('template.html', context,
                                  context_instance=RequestContext(request))
    

    You need to create the formset with the objects in the present page, otherwise, when you try to do formset = FormSet(request.POST, request.FILES) in the POST method, Django raises a MultiValueDictKeyError error.

    In the template.html file:

    {% if objects %}
        <form action="" method="post">
            {% csrf_token %}
            {{ formset.management_form }}
            {% for form in formset.forms %}
                {{ form.id }}
                <!-- Display each form -->
                {{ form.as_p }}
            {% endfor %}
            <input type="submit" value="Save" />
        </form>
    
        <div class="pagination">
            <span class="step-links">
                {% if objects.has_previous %}
                    <a href="?page={{ objects.previous_page_number }}">Previous</a>
                {% endif %}
    
                <span class="current">
                    Page {{ objects.number }} of {{ objects.paginator.num_pages }}
                </span>
    
                {% if objects.has_next %}
                    <a href="?page={{ objects.next_page_number }}">next</a>
                {% endif %}
            </span>
        </div>
    {% else %}
        <p>There are no objects.</p>
    {% endif %}