我有一个模型表单集(model formset),想要使用Django的Paginator每次显示10个表单,但是不能像这样做:paginator = Paginator(formset, 10)
。如果有办法,正确的做法是什么?
这是我发现用于解决问题的通用示例:
在 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
之外的其他错误。 - Lord ElrondPage
对象上设置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])
更正确的使用方法
...
formset = FormSet(queryset=page_query.object_list)
...
BaseModelFormSet
需要QuerySet
对象,而且会在使用list
时失败。 - Gill BatesCannot filter a query once a slice has been taken.
@GillBates: object_list
返回的是一个 QuerySet
,而不是一个 list
。所以请使用 @Filly 的答案! - CaumonsPage
)在期望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)
同意Elrond Supports Monica。虚假属性是解决排序错误(无法在切片后重新排序查询)的有趣方法。
但也可以用一行代码来解决:
queryset = queryset.order_by(Entry._meta.pk.name)
这种虚假排序是为了避免在django.form.modelsBaseModelFormSet(BaseFormSet).get_queryset(): line #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)
https://code.djangoproject.com/ticket/30632
- Beki