对Django表单POST请求结果进行分页

20 投票
8 回答
14917 浏览
提问于 2025-04-15 19:18

我正在使用Django表单通过POST进行过滤搜索,并希望使用Django的分页器类来整理结果。请问在不同页面之间传递客户端时,如何保留原始请求?换句话说,当我把GET请求传回我的视图以获取另一个页面时,似乎会丢失POST数据。我看到有些建议使用AJAX来仅刷新页面的结果部分,但我想知道是否有Django自带的机制可以做到这一点。

谢谢。

8 个回答

6

正如@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']
""" ... """

更多信息可以在 这里 找到

8

看到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})

希望这对你有帮助!如果有人有任何改进的建议,欢迎提出。

28

如果你想在后续请求中访问存储的数据,你需要把这些数据存储起来。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 只会更新你的结果列表,所以这些变量不会丢失。

撰写回答