【问题标题】:Paginate Django formset分页 Django 表单集
【发布时间】:2012-12-26 13:38:49
【问题描述】:

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

【问题讨论】:

  • 我也花了很多时间试图找出这个问题。原来我(我们)的想法是完全错误的。为什么要对表单集进行分页?您一次只能编辑一个页面,对吗?因此,像往常一样对整个查询进行分页,并只为单个页面制作表单集!繁荣。 https://code.djangoproject.com/ticket/30632

标签: python django paginator formsets


【解决方案1】:

这是我找到的解决问题的通用示例:

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

您需要使用当前页面中的对象创建表单集,否则,当您尝试在 POST 方法中执行 formset = FormSet(request.POST, request.FILES) 时,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 %}

【讨论】:

  • 强调“您需要使用当前页面中的对象创建表单集”。除了MultiValueDictKeyError 之外,您可以并且将会收到错误
【解决方案2】:

更优雅的解决方案是在Page 对象上设置ordered=True,以便可以将其传递给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])

【讨论】:

    【解决方案3】:

    更正确的使用方法

    ...
    formset = FormSet(queryset=page_query.object_list)
    ...
    

    【讨论】:

    • 你能详细说明一下吗?看起来很有趣。
    • 这不起作用,因为BaseModelFormSet 需要QuerySet 对象,并且会因list 而失败
    • 这会导致以下错误:Cannot filter a query once a slice has been taken. @GillBates: object_list 返回 QuerySet,而不是 list。所以使用@Filly 的答案!
    【解决方案4】:

    这里的问题是您在期望QuerySet 的上下文中使用品牌(Page)。所以,我们需要那个该死的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)
    

    【讨论】:

      【解决方案5】:

      同意Elrond Supports 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)
      

      【讨论】:

        猜你喜欢
        • 2011-12-11
        • 2013-04-15
        • 1970-01-01
        • 2021-07-07
        • 2020-11-17
        • 2021-05-02
        • 2012-08-17
        • 2012-03-14
        • 2018-02-08
        相关资源
        最近更新 更多