对Django表单POST请求结果进行分页
我正在使用Django表单通过POST进行过滤搜索,并希望使用Django的分页器类来整理结果。请问在不同页面之间传递客户端时,如何保留原始请求?换句话说,当我把GET请求传回我的视图以获取另一个页面时,似乎会丢失POST数据。我看到有些建议使用AJAX来仅刷新页面的结果部分,但我想知道是否有Django自带的机制可以做到这一点。
谢谢。
8 个回答
正如@rvnovaes所说,可以用会话(session)来解决这个问题。
不过他的方法有个缺点,就是如果搜索框很多,你就得写很多行代码。而且如果你在结果页面上显示搜索表单,所有的输入框都会变成空的,实际上它们应该保留之前的输入值。
所以我更倾向于把所有的表单数据保存在会话里,然后在页面加载时,如果会话存在,就强制设置请求中的数据和请求的方法:
""" ... """
if not request.method == 'POST':
if 'search-persons-post' in request.session:
request.POST = request.session['search-persons-post']
request.method = 'POST'
if request.method == 'POST':
form = PersonForm(request.POST)
request.session['search-persons-post'] = request.POST
if form.is_valid():
id = form.cleaned_data['id']
""" ... """
更多信息可以在 这里 找到
看到tux21b给出的很棒的回答,我决定实现第一个选项,也就是使用会话来存储查询。这是一个搜索房地产数据库的应用。下面是视图代码(使用django 1.5):
def main_search(request):
search_form = UserSearchForm()
return render(request, 'search/busca_inicial.html', {'search_form': search_form})
def result(request):
if request.method == 'POST':
search_form = UserSearchForm(request.POST)
if search_form.is_valid():
# Loads the values entered by the user on the form. The first and the second
# are MultiChoiceFields. The third and fourth are Integer fields
location_query_list = search_form.cleaned_data['location']
realty_type_query_list = search_form.cleaned_data['realty_type']
price_min = search_form.cleaned_data['price_min']
price_max = search_form.cleaned_data['price_max']
# Those ifs here populate the fields with convenient values if the user
# left them blank. Basically the idea is to populate them with values
# that correspond to the broadest search possible.
if location_query_list == []:
location_query_list = [l for l in range(483)]
if realty_type_query_list == []:
realty_type_query_list = [r for r in range(20)]
if price_min == None:
price_min = 0
if price_max == None:
price_max = 100000000
# Saving the search parameters on the session
request.session['location_query_list'] = location_query_list
request.session['price_min'] = price_min
request.session['price_max'] = price_max
request.session['realty_type_query_lyst'] = realty_type_query_list
# making a query outside the if method == POST. This logic makes the pagination possible.
# If the user has made a new search, the session values would be updated. If not,
# the session values will be from the former search. Of course, that is what we want because
# we want the 'next' and 'previous' pages correspond to the original search
realty_list_result = FctRealtyOffer.objects.filter(location__in=request.session['location_query_list']
).filter(price__range=(request.session['price_min'], request.session['price_max'])
).filter(realty_type__in=request.session['realty_type_query_lyst'])
# Here we pass the list to a table created using django-tables2 that handles sorting
# and pagination for us
table = FctRealtyOfferTable(realty_list_result)
# django-tables2 pagination configuration
RequestConfig(request, paginate={'per_page': 10}).configure(table)
return render(request, 'search/search_result.html', {'realty_list_size': len(realty_list_result),
'table': table})
希望这对你有帮助!如果有人有任何改进的建议,欢迎提出。
如果你想在后续请求中访问存储的数据,你需要把这些数据存储起来。Django提供了几种方法来实现这一点:
1) 使用 会话 来存储查询: 每个访问你网站的访客都会得到一个空的会话对象,你可以在这个对象里存储任何你想要的数据,它的作用就像一个字典。不过缺点是:同一个访客不能同时进行多个带分页的搜索。
2) 使用 cookies: 如果你设置了一个存储在客户端的 cookie,浏览器会把这个 cookie 的数据附加到每个请求中,你可以访问这些数据。Cookies 对服务器更友好,因为你不需要在服务器上管理会话,但存储在 cookies 中的数据对客户端是可见的(并且可以编辑)。缺点:和之前一样。
3) 使用隐藏字段: 你可以在搜索结果页面添加一个表单,并在其中放一些隐藏字段来存储查询。然后,每当你提交表单时,客户端会重新发送这个查询。缺点是:你必须使用带有提交按钮的表单来进行分页(简单的链接是无法工作的)。
4) 创建包含查询的链接: 你可以使用 GET 而不是 POST。例如,你可以有一个链接像 "/search/hello+world/?order=votes"
,还有“分页链接”像 "/search/hello+world/2/?order=votes"
。这样,查询就可以很容易地从 URL 中获取。缺点是:通过 GET 发送的数据量是有限制的(但对于简单搜索来说,这通常不是问题)。
5) 使用组合方法: 你可以把所有数据存储在会话或数据库中,通过生成的键来访问这些数据,并把这个键放在 URL 中。这样,URL 可能看起来像 "/search/029af239ccd23/2"
(表示第 2 页),你可以用这个键来访问之前存储的大量数据。这解决了方案 1 和方案 4 的缺点。新的缺点是:工作量会比较大 :)
6) 使用 AJAX: 通过 AJAX,你可以把数据存储在客户端的一些 js 变量中,然后可以在其他请求中传递这些变量。而且因为 AJAX 只会更新你的结果列表,所以这些变量不会丢失。