在保留GET信息的同时从django中的url中删除查询字符串

时间:2013-08-08 16:48:04

标签: django django-views

我正在开发一个Django设置,我可以在其中收到一个包含查询字符串的URL作为GET的一部分。我希望能够处理查询字符串中提供的数据,并返回针对该数据调整但不包含URL中的查询字符串的页面。

通常我会使用reverse(),但我不确定如何在这种情况下应用它。以下是具体情况:

示例网址 .../test/123/?list_options=1&list_options=2&list_options=3

urls.py

urlpatterns = patterns('', 
    url(r'test/(P<testrun_id>\d+)/'), views.testrun, name='testrun')
    )

views.py

def testrun(request, testrun_id):
    if 'list_options' in request.GET.keys():
        lopt = request.GET.getlist('list_options')
        :
        :
        [process lopt list] 
        :
        :

    :
    :
    [other processing]
    :
    :

    context = { ...stuff... }
    return render(request, 'test_tracker/testview.html', context)

当处理示例URL时,Django将返回我想要的页面,但URL仍然包含末尾的查询字符串。剥离不需要的查询字符串的标准方法是使用return HttpResponseRedirect(reverse('testrun', args=(testrun_id,)))返回testrun函数。但是,如果我在这里这样做,那么我将通过testrun函数获得无限循环。此外,我不确定原始请求中的list_options数据在重定向之后是否仍然可用,因为它已从URL中删除。

我该如何解决这个问题?我可以看到将list_options变量的解析移到一个单独的函数中以避免无限递归可能是有意义的,但是如果我这样做的话,我担心它会从请求中丢失list_options数据。有没有一种巧妙的方法可以同时从URL的末尾删除查询字符串并在一个地方返回我想要的页面,这样我就可以避免将各个单独的内容分成多个函数?

编辑:一些额外的背景,因为有几个“你为什么要这样做?”查询。

我正在设计的网站是报告我正在处理的软件的各种测试结果。这个特定页面用于报告单个测试的结果,通常我会从更大的测试列表链接到它。

list_options数组是一种指定我刚刚来自的列表中的其他测试的方法。这允许我使用其他相关测试填充下拉菜单,以便我可以轻松地在它们之间切换。

因此,我很容易最终传递15-20个不同的值并创建大量的URL,我想避免这些。如果我没有在URL中建议任何其他内容,那么该页面将设计为具有一组默认的其他测试以填充相关菜单,因此如果我删除list_options,这不是什么大问题。如果用户希望直接返回页面,他将不关心列表中的其他测试,因此如果该信息不可用则不会出现问题。

1 个答案:

答案 0 :(得分:2)

首先要小心谨慎。出于各种原因,这可能不是一个好主意:

  • 书签即可。想象一下,.../link?q=bar&order=foo将过滤一些搜索结果,并按特定顺序对结果进行排序。如果您将自动删除查询字符串,那么您将有效地禁止用户为特定搜索查询添加书签。
  • 测试即可。无论何时添加任何自动化,事情都可能并且可能以您从未想象过的方式出错。坚持使用简单而有效的方法总是更好,因为它们被广泛使用,因此不易出错。我在下面给出一个例子。
  • <强>维护即可。这不是一个标准的行为模型,因此这将使未来的开发人员更难以进行维护,因为他们首先必须先了解正在发生的事情。

如果您仍想实现这一目标,最简单的方法之一就是使用会话。我们的想法是,当存在查询字符串时,将其内容保存到会话中,然后在没有查询字符串时检索它。例如:

def testrun(request, testrun_id):
    # save the get data
    if request.META['QUERY_STRING']:
        request.session['testrun_get'] = request.GET
        # the following will not have querystring hence no infinite loop
        return HttpResponseRedirect(reverse('testrun', args=(testrun_id,)))

    # there is no querystring so retreive it from session
    # however someone could visit the url without the querystring
    # without visiting the querystring version first hence
    # you have to test for it
    get_data = request.session.get('testrun_get', None)
    if get_data:
        if 'list_options' in get_data.keys():
            ...
    else:
        # do some default option
        ...

    context = { ...stuff... }
    return render(request, 'test_tracker/testview.html', context)

这应该可行,但它可以很容易地破解,并且没有办法轻易修复它。这应该说明上面的第二个子弹。例如,假设用户想要并排比较两个搜索查询。因此,他会尝试在同一浏览器的不同标签中访问.../link?q=bar&order=foo`.../link?q=cat&order=dog。到目前为止一切都很好,因为每个页面都会打开正确的结果,但是一旦用户尝试刷新第一个打开的选项卡,他就会从第二个选项卡中获得结果,因为这是当前存储在会话中的内容,因为浏览器将有一个两个标签的单个会话令牌。

即使你会发现一些其他方法来实现你想要的而不使用会话,我想你会遇到类似的问题,因为HTTP是无状态的,因此你必须在服务器上存储状态。

实际上有一种方法可以在不破坏大部分功能的情况下执行此操作 - 在客户端而不是服务器端存储状态。因此,您将拥有一个没有查询字符串的URL,然后让javascript查询某些API,以便在该页面上显示任何内容。然而,这将迫使您制作某种API并使用一些不完全属于您的问题范围的JavaScript。所以有可能干净利落,但这不仅仅涉及使用Django。