9

我有一个模型表单集,我想使用 Django 的 Paginator 一次显示 10 个表单,但不能像paginator = Paginator(formset, 10). 如果有办法,这样做的正确方法是什么?

4

5 回答 5

17

这是我发现的问题解决方案的一个通用示例:

forms.py文件中:

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

views.py文件中:

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))

您需要使用当前页面中的对象创建表单集,否则,当您尝试formset = FormSet(request.POST, request.FILES)在 POST 方法中执行时,Django 会引发 MultiValueDictKeyError 错误。

template.html文件中:

{% 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 %}
于 2013-01-02T20:41:29.717 回答
3

一个更优雅的解决方案是ordered=TruePage对象上设置,以便可以将其传递给ModelFormSet.

这是一个例子:

forms_per_page = 10
current_page = 1

ModelFormSet = modelformset_factory(MyModel, form=MyForm)
queryset = MyModel.objects.all()

paginator = Paginator(queryset, forms_per_page)
page_object = paginator.page(current_page)
page_object.ordered = True

form = ModelFormSet(queryset=page_object)

这比接受的答案更有效,因为避免了在该行中发生的第二个数据库查询:

page_query = query.filter(id__in=[object.id for object in objects])
于 2019-12-29T03:06:09.567 回答
2

更正确的使用方法

...
formset = FormSet(queryset=page_query.object_list)
...
于 2013-03-15T14:33:22.290 回答
0

这里的问题是您在Page期望 a 的上下文中使用品牌 (a ) QuerySet。所以,我们需要那个该死的QuerySet. 您的方法正确,但代码很多。

在源代码中,我们有:

class Page(collections.Sequence):

    def __init__(self, object_list, number, paginator):
        self.object_list = object_list
        self.number = number
        self.paginator = paginator
        ...

所以,我们的查询集在self.object_list属性中,只需使用它!

formset = SomeModelFormSet(queryset=objects.object_list)
于 2014-12-28T00:04:11.927 回答
0

同意Elrond 支持 Monica。假属性是解决排序错误的有趣方法(一旦获取切片,就无法重新排序查询。)

但它也可以固定在一行中 queryset = queryset.order_by(Entry._meta.pk.name)

这种虚假排序需要避免django.form.modelsBaseModelFormSet(BaseFormSet).get_queryset() 中的错误:第 640 行
通过 pk 进行人工排序,但切片后不可能(SQL 中的限制)

更详细的例子

    queryset = Entry.objects.all()
    queryset = queryset.order_by(Entry._meta.pk.name)

    paginator = Paginator(object_list=queryset, per_page=10)
    page_obj = paginator.get_page(request.GET.get('page'))

    EntryFormSet = modelformset_factory(Entry, EntryForm, extra=0)
    entryformset = EntryFormSet(queryset=page_obj.object_list)
于 2020-11-02T20:24:03.247 回答