17 feb 2013

[HOW TO] Paginate a Django formset

Last month I needed to paginate a Django model formset and I couldn't find the way to do it, but I found posts asking the same question without an answer, so here is my solution:

In the forms.py file: 

class MyForm(ModelForm):
    class Meta:
        model = MyModel
        fields = ('description',)
In the views.py file:

FormSet = modelformset_factory(MyModel, form=MyForm, extra=0)
if request.method == 'POST':
    formset = FormSet(request.POST, request.FILES)
    if formset.is_valid():
        formset.save()
    return HttpResponse('Formset submited!')
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 = MyModel.objects.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:

{% extends "base.html" %}
{% block content %}

Paginated formset

{% if objects %}
{% csrf_token %} {{ formset.management_form }} {% for form in formset.forms %} {{ form.id }}

Name: {{ form.instance.name }}

{{ form.as_p }}
{% endfor %}
{% else %}

There are no objects.

{% endif %} {% endblock %}

3 comentarios:

  1. Hay apps que te lo dan todo mascado para que no tengas que meter nada en la vista (solo la consulta). Yo estoy usando esta en mis proyectos:
    https://github.com/ericflo/django-pagination

    ResponderEliminar
    Respuestas
    1. django-pagination, al igual que el Paginator de Django, no soporta paginación de formsets. De ahí que mi problema requiriera la solución que posteé.

      Eliminar